Here you can put SciTECO macros that are neither suitable for the macro library that ships with SciTECO, nor for inclusion into the SciTECO language itself. These are typically macros you would add to your SciTECO profile (~/.teco_ini
).
Nevertheless you will find yourself writing many small macros for everyday use.
If you catch yourself copying these macros over and over again, why not share them here?
Some of the macros here might one day grow into a part of the standard library.
When adding a macro to this page, please
- add a subheading per macro, explaining its parameters and semantics
- insert the macro as a code block
- avoid using unprintable characters, i.e. write ^A
instead of ASCII code 1, avoid using the default escape string termination, etc.
- make sure the macro is valid SciTECO code, so it can be pasted into a SciTECO script file directly
- try to avoid platform-dependencies and undesired side-effects, e.g. the search/replace registers should be backed up if you modify them, etc.
Warning: The macros on this page might require a recent Git revision of SciTECO. The existing SciTECO releases might be too outdated. In other words, you may either have to try a nightly build or manually build SciTECO to use them.
The following macro implements indentation of code blocks.
^I
command.
Empty lines are left empty.
Negative values remove one level of indentation, handling hard as well as
soft tabs.
One is implied if the argument is missing.For instance, 10M#it
will indent the next 10 lines.
@^U#it{[:
"~1'U.i "~1'U.c
Q.i">
Q.i<
0A-10"N 0A-13"N Q.c<@^I//> ''
:L;>
|
-Q.i< Q.c<
0A-9"=D | @ES/GETTABWIDTH//<0A-^^ "N1;'D> '
> :L;>
'
]:}
Suppose you have an APL keyboard layout, you might want to define macros M→
and M←
for right and
left indentation respectively:
@^U→{:M#it}
@^U←{"~1'*-1M#it}
To further simplify calling these macros, you might want to define the following key macros in the “start” state:
@^U[^K→]{m→} 1^_U[^K→]
@^U[^K←]{m←} 1^_U[^K←]
This exposes the indentation as a single keypress of “→” or “←”.
The following macro M{
takes a line or character range (analogous to Xq
) and stashes the given part of the buffer into a temporary Q-register.
Dot is left at the beginning of this Q-register.
When called without arguments, M{
takes the entire last matched pattern (as by ^Y
).
0U[structs.len]
@^U[{]{
"~ ^YU.tU.f |
U.t "~ .U.f ^E@ES/LINEFROMPOSITION//+Q.t@ES/POSITIONFROMLINE//:^EU.t | U.f ' '
Q.fU[structs.^E\[structs.len].from] Q.tU[structs.^E\[structs.len].to]
Q.f,Q.tX[structs.^E\[structs.len]] @EQ[structs.^E\[structs.len]]//
%[structs.len]$
}
The user is supposed to perform edit operations on this temporary buffer and eventually call the macro M}
,
which takes no arguments:
@^U[}]{
-%[structs.len]"=
Q*U*
|
-%[structs.len]$ @EQ[structs.^E\[structs.len]]// %[structs.len]$
'
.U..
Q[structs.^E\[structs.len].from]J
.-Q.."< :Q[structs.^E\[structs.len]]-Q[structs.^E\[structs.len].to]+Q[structs.^E\[structs.len].from]%..$ '
Q[structs.^E\[structs.len].from],Q[structs.^E\[structs.len].to]D
G[structs.^E\[structs.len]]
Q..J
!!:FQ[structs.^E\[structs.len].] FQ[structs.^E\[structs.len]]
}
M}
replaces the buffer range - specified by M{
- with the contents of the temporary Q-register buffer.
Calls to M{
and M}
can be nested.
Code between M{
and M}
can be read as “to be applied on the given buffer range”.
This construct is particularly useful in situations where operations cannot easily be bound to a given range, especially search-replace operations.
For instance 3M{ <@FR/^EM^ED/0/;> M}
will replace all integers with “0”, but only in the next 3 lines, regardless of the fact that the search-replace operation can delete characters. This would be very cumbersome to script with a per-line loop.
These macros are especially powerful after plain search commands (S
or N
) as the range to be extracted and edited defaults to the last search result.
This effectively brings the power of structural regular expressions, as pioneered by the editor Sam, to SciTECO.
For instance, <@S/{^EM^N}}/; M{ <@FR/^EM^ED/0/;> M}>
will replace all integers with “0”, but only within all braces.
This could easily be adapted to perform operations on all balanced braces, etc.
You can also add reverse conditionals to restrict which matches are processed thanks to the power of the ^Y
command.
For instance, <@S/{^EM^N}}/; ^Y:@S/foo/"F M{ <@FR/^EM^ED/0/;> M} '>
will replace integers with “0” in all braces, that don’t contain the string “foo”. Note that a failing search will not overwrite the buffer ranges returned by ^Y
.
M{
while editing a Q-Register.
The corresponding M}
will return to the last edited file buffer instead.
We cannot currently query and store which Q-Register is edited and not even whether any Q-Register is edited at all.FQ
(forget Q-Register) command.
But I don’t expect this to be a problem in practice.The following macro - invoked m#cf
- wraps ClangFormat to format a block of code according to various coding styles. Dot is always left at the equivalent position in the code after the formatting procedure. The binary is expected to be called clang-format17
, although this can be changed easily in the macro’s definition. The macro also expects jq to be in the executable PATH - it is used for parsing JSON emitted by ClangFormat. There should be packages for both tools for your favorite Linux distribution and the macro should work on Windows and obscure systems as well.
The coding style to use is specified by the global register cf.style
(corresponding with ClangFormat’s -style
option). By default, a file .clang-format
is looked up in all the parent directories to determine the settings, allowing you to add .clang-format
files on a per-project basis. Using this scheme, default settings could for instance be placed in ~/.clang-format
.
1M#cf
formats the next line, 0M#cf
formats the current line etc.In other words, the semantics are compatible e.g. with the K
or X
commands.
@^U[cf.style]'file'
@^U#cf{
U.l "~
!* line range *!
^EU.[offset] ^E@ES/LINEFROMPOSITION//+Q.l@ES/POSITIONFROMLINE//-^EU.[length]
Q.[length]"< Q.[length]%.[offset]$ -1*Q.[length]U.[length] '
|
!* char range *!
^EU.[offset] Q.l^E-Q.[offset]U.[length]
'
^EU.[cursor]
:Q*"> @EU.[filename]'-assume-filename=^E@*' | @^U.[filename]'' '
!* Disable EOL-conversions and enable UNIX98 shell emulation *!
EDU.e 16,128ED
H@EC'clang-format17 -offset=^E\.[offset] -length=^E\.[length] -cursor=^E\.[cursor] ^EQ.[filename] -style=^E@[cf.style]'
!* first line contains new cursor (JSON-encoded) *!
J 1@EC'jq -r .Cursor' J\U.[cursor] K
Q.[cursor]:^EJ
Q.eED
}
This macro can be used to annotate the current buffer with commit information akin to git-blame. The shortened commit that changed a line will be shown in the margin next to the line number.
Since SciTECO currently does not support margin setups via built-in commands, but only via ES
,
this will not undo the margins when being rubbed out.
You can call -M[git.blame]
to hide the corresponding margins.
@^U[git.blame]{
"~1'"S
!* Disable blame margins *!
3@ES/SETMARGINWIDTHN//$
4@ES/SETMARGINWIDTHN//$
$$
'
HX.b
!* Disable EOL-conversions and enable UNIX98 shell emulation *!
EDU.e 16,128ED
[*[_[$
@EQ*'' ZJ -@S'/' .,ZX.#bn 0,.X$
@EQ.b'' H@EC'git blame --incremental --contents - -- ^E@.#bn'
!*
* Shorten _some_ hash to get a minimal display size, taking Git settings into account.
* This size should be sufficient for all other hashes as well.
*!
@EG.[HEAD]'git rev-parse --short HEAD'
J< .-Z;
.U.h 2W\U.s W\U.l
Q.l< Q.h,Q.h+:Q.[HEAD]-1X.[margin.^E\.s] %.s>
@S'^Jfilename ' L
>
]$]_]*
Q.eED
4,3@ES/SETMARGINTYPEN//$
33@ES/TEXTWIDTH/9/U.w
(:Q.[HEAD]-1)*Q.w,3@ES/SETMARGINWIDTHN//$
Q.w,4@ES/SETMARGINWIDTHN//$
1U.s <
:Q.[margin.^E\.s]:;
Q.s-1@ES/MARGINSETTEXT/^EQ.[margin.^E\.s]/$
%.s>
}
TODO: If we do something analogous for Subversion and Mercurial, it might be a prime candidate for adoption
into the standard library.
It already contains some VCS integration in sessions.tes
.
The following macro allows spell checking via aspell.
Unknown words, which are not in the aspell.dicts
dictionaries, are underlined with squiggles on Gtk or highlighted on Curses.
The aspell.styles
registers restrict spell checking to individual lexer states
based on the numeric lexer id.
Currently, it must always be invoked manually, ie. by typing M#sp
.
Use -M#sp
to clear all spell checking indicators.
@^U[aspell.styles.2]"1,12" !* python: all comments *!
@^U[aspell.styles.3]"1,2" !* cpp: all non-doc comments *!
@^U[aspell.styles.15]"1,2,3" !* lua: all comments *!
@^U[aspell.styles.137]"0,5" !* troff: text and string arguments *!
@^U[aspell.dicts]"en"
@^U#sp{
"~1'U.s
2@ES/SETINDICATORCURRENT//$
0EJ-1"=8|13',2@ES/INDICSETSTYLE//$
:^E,0@ES/INDICATORCLEARRANGE//$
Q.s"S $$ '
@ES/GETLEXER//U.#lx
:Q[aspell.styles.^E\.#lx]-1"<
!* spellcheck everything *!
HX.b [* @EQ.b// J<@I"^^" :L;> ]*
|
!* spell check per style *!
:M[aspell.styles.^E\.#lx],-1:<"~1;'U.s (-U.[styles.^E\.s])>
!* Make sure that everything is already styled as we spell check per style: *!
:^E,0@ES/COLOURISE//$
[: J @^U.b"^"
< .-Z"=1;' 0A-10"=
:@EU.b"^J^^"
|
^E@ES/GETSTYLEINDEXAT//U.s
:Q.[styles.^E\.s]"F 0A | 32 ':@^U.b//
' :C;>
]:
'
[* @EQ.b//
!* Disable EOL-conversions and enable UNIX98 shell emulation *!
EDU.e 16,128ED
H@EC"aspell -d ^E@[aspell.dicts] --dont-guess --dont-suggest --byte-offsets -a"
Q.eED
J < .-Z"=1;'
0A-10"=
%.l$
| 0A-^^#"= !* word not found *!
2C ^EU.w W ^E-1-Q.wU.w \U.o
]*
Q.w,(Q.l@ES/POSITIONFROMLINE//+Q.o-1)@ES/INDICATORFILLRANGE//$
[* @EQ.b//
' '
:L;>
]*
}
TODO: It should be possible to invoke the spell checking macro automatically, at least after buffers are dirtified. Still, even then, it would not be undoable unless we add proper SciTECO commands for manipulating the indicators. This macro can also be significantly optimized.
The following macro - invoked m#mk
- simply runs make
and saves its output (both stdout and stderr) in the global Q-Register “make.output”. If make
fails (usually caused by a compilation error), “make.output” is made the currently edited Q-Register so the errors are brought to your attention.
Since SciTECO’s current working directory is seldom the directory you want make
to run in (and look for Makefiles), this macro runs make
in the directory specified by the global Q-Register “make.dir”. This is useful when building out-of-tree since there is no way to automatically determine the directory you want make
to use. If “make.dir” is empty or undefined (the default), this macro will run make
in the directory of the current buffer instead, which should be fine for in-tree builds most of the time. If not set @EU[make.dir]'^EQ$'
or hack the macro :-). You could even make “make.dir” persistent per buffer session by saving it in a file alongside .teco_session
(see sessions.tes
)…
@^U#mk{ [$
:Q[make.dir]">
@FG'^EQ[make.dir]'
|
[_ @EQ*'' ZJ -:@S'/'"S 0,.X$ ' ]_
'
@EQ[make.output]'' HK
:@EC'make 2>&1'"S Q*U* '
]$ }
The following macro closes the current XML tag “automatically” taking XML comments and CDATA-sections into account. I doubt however that it implements all the lexical rules of XML.
The macro takes no arguments and can be invoked by calling M#</
.
@^U#</{
[_ .U.i
<
-@S'^N/>';
!* skip CDATA sections *!
3R ::@S']]>'"S -@S'<![CDATA[' F< '
-@S'<'
!* skip comments *!
0A-^^!"= F< '
0A-^^/"N-'%.l"<
.(@S'^E[ ,^I,>]'R.)X.n 1;
'
>
Q.iJ :Q.n"> @I'</^EQ.n>' '
]_
}
Here’s a variant of the same functionality as a command line editing macro.
Whenever you type M#</
, the macro call at the end of the command line will be replaced with the insertion of the closing XML tag. If no appropriate tag could be found, it just rubs out the macro call.
@^U#</{
<
-@S'^N/>';
!* skip CDATA sections *!
3R ::@S']]>'"S -@S'<![CDATA[' F< '
-@S'<'
!* skip comments *!
0A-^^!"= F< '
0A-^^/"N-'%.l"<
.(@S'^E[ ,^I,>]'R.)X.n 1;
'
>
{ -3D
:Q.n"> @I'I</^EQ.n>^[' '
}
}
The following macro will reflow the current paragraph, so it fits into the columns previously configured with SCI_SETEDGECOLUMN
.
If no edge column is configured, it defaults to 80 columns.
You can also pass in line and character ranges (like for the X
command).
Dot is always left at the current point in the reflowed range.
This macro is especially useful when writing plain text files and emails.
@^U#rf{[_
(.U..)
"~ -:@S/^J^J/"F J ' .,(:@S/^J^J/"SR.|Z') '@X.p .U.p
@ES/GETEDGECOLUMN//U.c Q.c"= 80U.c '
[* @EQ.p//
<@FD/^ES/; Q.p+.-Q.."< ^S+1%..$ ' @I/ />
J <Q.c:C; -@FS/ /^J/;>
ZJR ::@FS/ /^J/$
]* G.p Q..J
]_}
Jumps to the end of the next “function” - actually just to the end of the next pair of balanced curly braces. This is more or less sufficient in many languages that use curly braces for code blocks.
@^U#sf/ [_ (
<@S"^E[{,}]" -A-^^{"=1|-'%.n"=1;'>
) ]_ /
SciTECO does not currently contain a command to join two lines (i.e. remove the line break).
Fortunately, this operation is trivial to define as a macro.
The following macro accepts an optional line index (1 by default). So M#jn
joins the next line with the current one.
0M#jn
joins the current line with the previous one.
@^U#jn{
^Q+.U.x Q.x-1,Q.xD
}
Perhaps more useful would be joining a number of following or previous lines
while normalizing the spaces around the line break.
M#jn
should join the current with the next line,
while 2M#jn
joins the next 2 lines.
-M#jn
would join the current with the previous line and so on.
This could be done with the following macro:
@^U#jn{[_
%.l (.U..) "<-'Q.l<
Q.l"<-'@FD/^E[^EM ,]^J^E[^ES,]/; Q.l"< ^S+1%..$ ' @I/ /
>
Q..J
]_}
If you have a German keyboard layout, you may define the macro M§
as well.
It can be further be made a key macro in the “start” state, so pressing §
will also be sufficient.
@^U§{:M#jn}
@^U[^K§]{m§} 1^_U[^K§]
This macro is useful for finding the next line that exceeds a certain amount of characters - in case you want to break it into smaller lines. The column limit can be specified as a numeric parameter. If missing, it defaults to the edge column if previously set. Some lexers may set the edge columns to a sensible default. If no parameter is given, a limit of 80 characters is assumed. Dot is left at the next column after the limit.
Note that Scintilla also allows you to set up visual hints to highlight long lines using SCI_SETEDGEMODE
and related messages.
@^U#lc{
"~ @ES/GETEDGECOLUMN//U.c Q.c"= 80U.c ' | U.c '
<LR ^E@ES/SCI_GETCOLUMN//-Q.c">
Q.c+1,(^E@ES/SCI_LINEFROMPOSITION//)@ES/SCI_FINDCOLUMN//:^EJ 1;
' L>
}
The following macro turns SciTECO into something like a hex editor
for editing binary files.
You should probably launch it with sciteco -8
.
Executing M#hx
displays all non-alphanumeric characters
in the buffer with special hexadecimal character representations.
If called as -M#hx
all bytes are displayed with hexadecimal
representations.
@^U#hx{
"~1'U.a
0EE
3@ES/SETLAYOUTCACHE//$ 1000@ES/SETLAYOUTTHREADS//$ !* cache entire document *!
1@ES/SETVIEWEOL//$
!!2@ES/SETWRAPMODE//$
@ES/SETREPRESENTATION/^@00/$
@^U.x/0/ !* padding *!
254<
%.x-16"= @^U.x// '
Q.a"F Q.x"R F> ' '
16^R @ES/SETREPRESENTATION/^EU.x^@^EQ.x^E\.x/$ ^D
>
}
FIXME: Scintilla will display EOL bytes, but still break lines after them.
Furthermore, it does not currently show tab characters as 09
.
Enabling per-character line wrapping is unfortunately very slow.
Scintilla generally has a performance problem with excessively long lines.
This macro opens the current buffer in a separate window at the same position (using opener.tes
)
and closes the current buffer afterwards.
It will fail if the current buffer is modified.
Effectively, it will “detach” the current buffer into an external window.
You may have to tweak the detach.newwin
register to your terminal emulator of choice (e.g. xterm -c sciteco
).
You could also match on $TERM to set different values (as in :@EN/xterm*/^EQ[$TERM]/"T @^U[detach.newwin]"xterm -c sciteco" '
).
This version of the macro works only on UNIX/Linux, but it may be possible to tweak it for Windows using the start
command.
0EJ-2"=
@^U[detach.newwin]'gsciteco'
|
@^U[detach.newwin]'st sciteco'
'
@^U#dt{
[*].b ^E@ES/LINEFROMPOSITION//+1U.l ^E@ES/GETCOLUMN//+1U.c EF
@EC'^EQ[detach.newwin] +^E\.l,^E\.c ^E@.b &'
}
Deletes the next camel-cased word beginning at the current buffer position.
E.g. if dot points to fooBar
, it will delete foo
.
@^U#nv{
(<:D; 0A"W1;'>)
}
A command-line editing macro that when executed, compresses a sequence of repeating characters at the end of the command-line into a number followed by that character.
It rubs out itself in the process. For instance if you have typed cccccccccc
and then type m#cm
, the c’s are compressed to 10c
.
@^U#cm{{
-3D -AU.c <."=1;' -A-Q.c"N1;' -D %.n> Q.n\ Q.c@I//
}}
NOTE: This macro is deprecated. You can always use SciTECO’s built-in clipboard support even on ncurses/UNIX. If OSC-52 clipboards are not supported by your terminal emulator, set $SCITECO_CLIPBOARD_SET
and $SCITECO_CLIPBOARD_GET
either in the environment or in ~/.teco_ini
. There is an example for xclip in fallback.teco_ini.
This is a wrapper for SciTECO’s built-in clipboard support including a fallback for platforms where SciTECO does not support clipboards natively. It allows you to copy buffer contents into the main/default system clipboard or paste the clipboard at the current position.
It requires the xclip tool to be installed for the fallback case. Your Linux distribution probably has a package for xclip
.
X
or EG
commands in case you wonder.
This form of the macro does not change the current document.If clipboards are supported natively, rubbing out the macro call will indeed restore the original clipboard contents. This does not happen when the xclip
fallback has to be used.
@^U#xc{
:Q~">
"~ G~ | X~ '
|
"~
@EC'xclip -selection clipboard -out'
|
!* EG will consume arguments on stack *!
@EG.n'xclip -selection clipboard -in >/dev/null'
'
'
}
14B Sep 28 21:20 ../