原文
88,dPYba,,adPYba, ,adPPYYba,
88P' "88" "8a "" `Y8
88 88 88 ,adPPPPP88
88 88 88 88, ,88
88 88 88 `"8bbdP"Y8
"ma" is a minimalistic clone of the acme[1] editor used in Plan 9,
and is written in Tcl/Tk. It has been tested with Tcl/Tk 8.5, mostly
under Linux and OpenBSD. "ma" has successfully been run on Mac OS
X with XQuartz, but needs a tiling window manager to be used in a
satisfactory way.
I used emacs[2] for years, but got bored with the ever growing
number of extensions and key-combinations that one has to remember
when intensively using that editor. I also got fed up with the fact
that purely keyboard driven interfaces involve frantic typing,
something that appears to stress me. Acme, which is heavily
mouse-controlled, seems to produce a more relaxed, single-handed
use, especially for navigation and browsing. I'm slower now (or at
least this is my impression), but less hectic while working (it
seems).
Another advantage of acme is the dynamic nature of extending the
user-interface while one is using it - nearly everything is text,
and every text can be mouse-sensitive.
Note that this editor is single-window based - it doesn't provide
multiple windows, nor does it manage them in any way (this is
delegated to the window manager.)
Installation:
Invoke
./build
and put the files "ma", "awd", "win", "pty", "plumb" and "B" in your
PATH and ".plumb" into your $HOME.
Usage:
"ma" attempts to work as much as possible like acme, but does no
own window-management. Configuration is done in the file "~/.ma",
holding Tcl code to modify fonts, colors, etc. A number of
command-line options can be provided to set various of these options
and to run "ma" in special modes, or to communicate with the
"registry", a "ma" instance that allows locating files that are
already open.
To start the registry, run
ma -registry &
The registry is implemented using the Tk "send" command, so
X-forwarding must be disabled (enter "xhost" to see wether this is
the case). "ma" should still run, but features related to the
registry will not be available in this case (locating already open
windows, and "Putall".)
The "B" program takes one ore more filenames (optionally followed
by an address) and opens the given files or activates already open
windows holding these files.
"pty" is a generic program running a subprocess in a pseudo terminal
and is used by "win" to have interactive windows inside a "ma"
instance. Note that this is currently very crude and does not support
escape codes of any kind.
"ma-eval" can be used to evaluate Tcl code in a running "ma" instance,
"awd" sets the label of the window in which the command is executed.
You can create an alias for "cd" to set the label automatically
when used inside an interactive shell window:
alias cd="_cd"
function _cd () {
\cd "$@"
if test -n "$MA"; then
awd bash
fi
}
When the registry is running, the window that has the current focus
is drawn with a white border around it. Executing commands in the
body of another window will then perform the execution in the context
of the focus window. Execution in the tag of a window always has
that window as context, regardless of focus.
When you create a new, unnamed window and want to save it, then
just edit the filename (initially ""). Also saving the
file under a different name can be done the same way.
The "plumb" program performs a very simple Plan-9 like "plumbing"
based on regular expressions, see ".plumb" for some examples on how
to define rules, which consists of Tcl code associated to regular
expressions. "plumb" takes a string as argument and runs the
plumbing rules in "~/.plumb" until a rule matches and succeeds.
Text sweeped or clicked with B3 will invoke "plumb" with the string
as argument.
Environment variables:
MA_HISTORY
If set, all code that is executed in "win" mode or via B2 is logged in
the file given in this variable (this includes all input, including
passwords!)
C_INCLUDE_PATH
Lists additional include-directories, separated by ":" (default:
"/usr/include")
SHELL
Shell to use for executing commands (default: "bash")
MA
Set to the name of the wish(1) instance when executing external
programs.
Access from the command line:
Using "ma-eval", some elements from a "ma" window can be
accessed by sending Tcl code to the process in which a shell command
was initiated:
For example,
ma-eval $MA GetBody
would print the contents of the window body to stdout. Here is a selection
of some useful Tcl commands that you can use (for more intricate access,
study the "ma" source code):
GetBody
GetTag
GetLabel
SetBody TEXT
SetTag TEXT
SetLabel TEXT
ReplaceFile FILENAME
GetDot
SetDot ADDRESSS
Insert TEXT
InsertFile FILENAME
Append TEXT
AppendFile FILENAME
Note that text may have to be suitable quoted to be passed trough
to the Tcl interpreter that is running in the window, like this:
ma-eval $MA Insert "{this is a test}"
Customization:
At the start of the "ma" script, you will find a number of global
variables that hold default values for fonts, colors and other
settings that are used throughtout the editor. Modify these at
your convenience.
Extending:
The easiest way to add commands is simply to put scripts or programs
in your PATH. If you want more thorough integration, you can also
define commands at the Tcl level, by using "DefineCommand REGEX
EXPR" to define Tcl code to be executed when the command given in
REGEX is executed, i.e.
DefineCommand {^MyCommand\s+(.+)$} { ... }
Arguments (subpatterns in the regex) can be extracted with "GetArg".
"ma" is not finished, and probably never will. For more information,
consult the source code or contact me[3].
To do:
- (bug) crash of program in win-mode doesn't print any message
- (bug) KeyRelease-event in .tag (getting through after invoking
dmenu(1) in this case) results in incorrect resize of tag, even
though only first line contains text
- (bug) Automatic resizing of the tag doesn't always work
- (bug) sort order in columnar listing is wrong (should be rowwise,
not columnwise)
- (bug) Tk seems to clear the clipboard when exiting, so the
contents copied from a terminated instance are not recovered
- (bug) the (pseudo-)selection is sometimes retained even after
input
- (bug) "Back" should not put position on search-stack if search
wraps around
- (bug) The exit status of subprocesses in non-win mode is silently
discarded. This seems to be a Tcl limitation, see also:
https://core.tcl.tk/tips/doc/trunk/tip/462.md
- (bug) the option "-post-eval Bottom" doesn't seem to work,
possibly due to RelayoutTag after wm-triggered resize
- (bug) Entering a window with a selection replaces the clipboard
contents with the selected text
Shortcomings:
- the file-registry needs to be explicitly started
- the "Kill" command (Del key) is not very reliable with respect to
what processes are killed (should probably use a process group)
- the width used for computing columnar directory layout seems not
to be correct (always 80?)
- autosnarf when selecting: no idea how to do this, keeping current
selection and copying when selection gets empty doesn't work,
since selection by mouse apparently clears it in between
movements; perhaps detect when selection changes from non-empty
to empty
- there is no "Zerox" command
- works very bad on Mac/Aqua and Windows:
- Mac: default Tcl/Tk crashes, freshly installed (Aqua) aborts
unexpectedly, B2/B3 are swapped, slow startup (note that
Tcl/Tk for XQuartz works surprisingly well, though)
- Windows: cursor in text widget barely visible (black, even on
dark background), startup very slow, binding Ctrl-keys doesn't
seem to work, UpdateTag doesn't seem to treat filename as valid
and inserts Win-style path before it (this is with Active
State Tcl/Tk, 8.6.4)
- there is no backup-file
- Address syntax only supports a subset of acme/sam and is rather
crude (see also comment in ParseAddr), "/.../"/"?...?" addresses
only select a position, not ranges
- In "win" mode, "ma" tries to ignore the prompt from input lines,
but moving the insertion point may confuse this, if possible use
a prompt for interactively used programs that will be ignored
by the client program (e.g. ":;" for sh(1) or ";" for rc(1))
- Password-entry in "win" mode works only when the insertion cursor
is not moved by mouse or cursor-movement keys
- "Putall" is implemented, but will save all files in all open
windows, even on virtual screens not currently visible
- there is no "Edit" command
- necessary access to state of undo-stack is only available in
Tcl/Tk 8.6, so "Undo"/"Redo" is not added to tag on demand.
Differences to the Plan 9 acme:
- There is no "move" box
- Tab does not insert "\t" but whitespace
- (obviously) single-window mode
- no dynamic update of undo/redo commands tag (Tcl/Tk 8.6 seems
to support access to the undo-stack, though)
- auto-chmod when saving file beginning with "#!/"
- missing commands: "Zerox", "Edit", "Incl"
- supports Key-Up/Down movement by line
- inserting with active selection doesn't snarf
- indentation-setting is window-local
- executing with redirection ("|...", ">...", "<... in="" mode="" invokes="" shell="" and="" does="" not="" send="" the="" command="" to="" process="" running="" window="" executing="" tag="" always="" has="" current="" as="" context="" body="" currently="" focussed="" registry="" is="" double-clicking="" opening="" bracket="" selects="" forward="" but="" quote-="" scanning="" works="" backwards="" acme="" both="" quotes="" only="" select="" indent-mode="" differently="" word="" under="" cursor="" defined="" ws-delimited="" parentheses="" win-mode:="" pressing="" return="" before="" insert="" point="" sends="" whole="" line="" much="" weaker="" block="" basic="" keyboard="" commands="" for="" mouse-less="" operation:="" c-1="" focus="" c-2="" selection="" c-3="" b3-search="" case-insensitive="" search="" with="" address="" means="" plain="" string="" regex="" supports="" various="" emacsish="" sequences="" provided="" by="" tk="" text="" widget="" c-r="" from="" dot="" end="" of="" file="" additional="" commands:="" anchor:="" add="" insertion="" into="" withdraw:="" hide="" tcl="" code:="" execute="" code="" crnl:="" toggle="" between="" unix="" line-terminator="" encoding="" back:="" jump="" back="" previous="" after="" interrupt:="" interactive="" subprocess="" ma="" highlights="" matching="" parens="" shift-b3="" equivalent="" b2="" acquiring="" an="" existing="" doesn="" warp="" mouse="" toggles="" a="" state="" whether="" directories="" are="" opened="" or="" new="" one="" terminates="" like="" exit="" status="" word-wrapping="" char-wrapping.="" idioms:="" remember="" that="" you="" have="" filename="" completion="" everywhere="" use="" it="" custom="" button="" this="" especially="" useful="" win-mode="" adding="" often="" repeated="" programs="" any="" can="" be="" b2-clicked="" when="" input="" requested="" also="" b2b1="" chords.="" avoid="" console="" temporary="" guide="" reduces="" typing="" position="" ...="" override="" env-vars="" using="" b3="" files="" used="" other="" contexts="" just="" ensure="" target="" activated="" double-click="" words="" quickly="" them="" sweeping="" quote="" parenthesize="" contain="" whitespace="" addresses="" simple="" hyperlinks="" label="" all="" script="" working="" on="" automatically="" saves="" executable="" if="" she-bang="" exists="" write="" directly="" directory="" windows="" sweep="" refresh="" simply="" enter="" double-b1="" execution="" unique="" marker="" separate="" sections="" around="" through="" source="" hereby="" placed="" public="" domain="" acknowledgements:="" thanks="" to:="" lucas="" sk="" tips="" suggestions.="" kooda="" fixing="" completely="" broken="" implementation="" pty.c="" he="" fixed="" problem="" paren-matching="" several="" improvements="" corrections.="" version="" history:="" fix="" quoting="" issue="" plumbing="" include="" selecting="" initial="" fresh="" tries="" harder="" make="" visible.="" file.="" esc="" now="" records="" press="" moves="" more="" according="" how="" i="" understand="" behaviour="" sam="" involves="" starts="" at="" start="" newly="" typed="" since="" last="" release="" increased="" scroll="" amount="" prior="" keys.="" added="" option.="" tag-relayout="" sensure="" remains="" program="" passed="" exit-status="" caller.="" parsing="" may="" enclosed="" single="" double="" quotes.="" detecting="" closing="" paren="" instead="" command.="" bar="" takes="" center="" reference="" point.="" bug="" broadcast="" procedure="" saving="" nonexistent="" failed="" error="" creating="" needed.="" shape="" default="" left-pointing="" arrow="" platforms="" undo="" applies="" b1b2="" mousechord="" again="" caused="" successful="" even="" no="" rule="" matched.="" separated="" variable="" font="" states.="" reversed="" scrollbar="" colors="" key="" filename-completion="" alternative="" ctrl-f.="" b1="" dynamically="" adjusted="" amount.="" win="" reduced="" some="" unnecessary="" redirection="" keeps="" result="" selected.="" getting="" effective="" worked="" had="" resulting="" confusion.="" inserts="" stream.="" view="" should="" format="" columns="" correctly="" been="" shown="" first="" time.="" beginning="" characters.="" result-string="" remote="" call="" via="" empty="" output="" produced.="" resolved="" symlinks="" locating="" keep="" visible="" area.="" c-keen="" attempt="" optimize="">> event handler which seems to be slow
on ssome machines.
- B2 can now be used to abort B3-sweeping.
- When "scroll" mode is off, try to keep start of output received by every external
command at top of screen.
- Pressing sends SIGINT instead of SIGKILL now.
- The "pty" programm catches SIGINT and propagates it to the process group.
- Location of existing windows via registry handles spaces in directory names
correctly.
- Filenames with single quote in label are correctly quoted using double quotes.
- Execution with redirection always uses body selection or whole body.
- Dropped the "Replace" command (use an external tools like sed(1) or "LR"
from ma-utils).
- Re-activation of directory window refreshes contents.
6
- C-k on end of line just deletes the newline and doesn't overwrite the cut buffer.
- On-demand update of tag for "Put", "Back".
- added read and write hooks.
- "Look" doesn't warp mouse pointer.
- All MA windows that are not directory listings or output windows track "dirty" state.
- "Put " always saves, regardless of the type of window.
- Dotfiles command for directories.
- Added several hooks for integrating the directory editor (diredit.tcl).
- New files have a default name ("").
- Removed tag marker, "dirty" state is indicated by tag font style (italic).
- Double-B1 on empty line does not highlight line.
- Extracted plumbing into separate tool ("plumb").
- If the label is changed and the file does not exist yet, save text even if unmodified.
- Removed "Wrap" and default to char-wrapping.
- Renaming and saving output window properly reregisters the window.
5
- When the label is updated, set the windows' title accordingly (suggested by Lucas Sköldqvist.)
- added termination_hook.
- Always enable word-wrap in win mode.
- Computing the word under the cursor ignores the label marker character.
- Added "Back" command to move insertion mark back to old position after search.
- Replaced pty.c with a version that doesn't eat CPU time and is much simpler (thanks to
Kooda)
4
- Corrected initial tag relayout.
- Resizing scrolls to bottom if "scroll" mode is on.
- Dropped "-noscroll" option, added "-scroll".
- Filename completion adds final "/" for directory only if it doesn't need quoting.
- Added "name_hook", moved "project" files into extension.
- Replaces some message-boxes with marked text in +Errors window.
- Revertion shows message when file is modified, similar to "Del".
- "Wrap" command is shown in tag by default.
- "Get FNAME" checks whether the current file is modified.
3
- "New" starts new instance in current context.
- "Send" just appends at end (as in acme).
- Added "Putall".
- final delimiter in "/.../" + "?...?" addresses is optional now.
- switching to existing window via B3 warps mouse pointer to current selection
or insertion point.
- got rid of spurious newlines in tag that where sometimes added.
- directory listing quotes with "\"", when filename includes "\''".
- text in tag window wraps correctly when the window is resized.
- ESC selects up to insertion point at last mouse click, not the clicked location.
- the "dirty" marker is filtered out in most cases of clicking the label.
- (mostly) correct handling of backspace when entering passwords in win-mode.
- B1B2B3 leaves file unmodified.
- C-k snarfs deleted text.
- B1-doubleclick in the empty space after a text line selects the complete line.
2
- added some improvements in built-in plumbing rules.
- the registry logs its actions inside its own text body.
- the scroll-area is grayed in "scroll" mode.
- failure to open file outputs error in "+Errors" window.
- auto-detection of line-end translation, CRNL line-temrinators are preserved.
- fixed problems in some uses of "catch" which didn't properly evaluate their arguments.
- directory listings quote filenames, when necessary.
- running subprocesses are now not killed on termination.
- added MA_LABEL environment variable for subprocesses.
- a clicked word does not include parentheses or brackets/braces now.
- the history file is now made user-accessible only when written.
- added (crude) support for password entry in win-mode.
- added "-fontstyle" option.
1
- initial release.
[1] http://acme.cat-v.org/
[2] https://www.gnu.org/software/emacs/
[3] [email protected]
[4] http://www.cs.yorku.ca/~oz/wily/
[5] http://www.cs.yorku.ca/~oz/wily/python.html
[6] http://www.linusakesson.net/programming/syntaxhighlighting/
[7] https://www.robertmelton.com/project/syntax-highlighting-off/