How Geany and Tcl can help each other

This Tcl software e_menu provides a context help on Tcl/Tk commands and keywords in Geany IDE seance as well as a system of context menus closely bound to Geany IDE, thus Geany being a helper for Tcl, Tcl/Tk being a helper for Geany IDE.

By context help I mean the following: while editing a file.tcl in Geany you can set the caret on desirable Tcl/Tk command/keyword and press Ctrl+F1 (or F1, if you map F1 smartly to Geany's context action) - after that you should get a help (man) page for the Tcl command/keyword.

Man pages of www.tcl.tk are remarkable with their giving a separate man page (as html file) for each single entry. So, we can organize their viewing on context base.

And Geany is remarkable with its customizing features and one of them is a context action. The action may be tuned and called for a word or text selection from popup menu or with a hotkey.

Below there is an attached zip file that provides this mutual helping of Tcl/Tk and Geany.


List of features

e_menu has the following features:

  • calling a context help for Tcl/Tk during Geany seance
  • Tcl/Tk help pages can be made and called offline for faster response
  • opening any number of menus containing any commands (programs) to run
  • passing a selected text to the menu commands to process
  • the selection can be passed as underlined (“_” instead of “ ”), 'plused' (“+” instead of “ ”) or stripped of special symbols (“, $, %, {}, [], <>, *)
  • commands can be run by itself and by shell in console box
  • commands can be run with or without waiting their completion
  • internal command %E %s means “edit/create in Geany a file(s) with name(s) = selected text”
    (opens/creates in Geany f1 f2 f3 files if %s=“f1 f2 f3”)
  • internal command %B ”%s“ means “browse an internet link = selected text”
  • internal command %Q “title” “message %s” means “ask a confirmation, possibly with selected text”
  • a batch of commands can be united under a single menu item
  • any command can be confirmed, with message box of title and text including Geany selection
  • commands can include backslashes as opposed to Unix's ”/“ (esp. for Windows)
  • a hierarchy of menus
  • a child menu can be called with or without waiting it, with or without closing its parent menu
  • a child menu can be called with closing its parent and calling back the parent after closing the child
  • menus can be called (or made afterwards) as 'stayed on the top'
  • menus can be called to stay at any desirable position with reasonable width
  • inactive menus are lowlighted as opposed to highlighted active ones
  • menu items can be bound to hotkeys F1-F12 (by default they are bound to 1-9a-z)
  • menu items and their underlying commands can include up to 10 counters of runs per a menu
  • menu items and their underlying commands can be supplied with current date/time
  • menus can be run just before running Geany (with some shell command file)
  • menus are independent applications and as such can be run independently on Geany
  • any menu item can be assigned to 'autorun' at start of e_menu (submenus including)
  • commands that are invisible in menu may be assigned to 'autorun' (submenus including)
  • Tcl command(s) can be assigned to 'autorun' at start of e_menu
  • menus can be edited in Geany 'on fly' and then re-read
  • when calling non-existent menu you are prompted to create it in Geany; so you can create all menu system 'on fly'
  • 'autorun' items and commands are also re-run when the menu is re-read
  • e_menu can be started with a pause to delay its initialization
  • items can be run repeatedly at intervals set in seconds
  • e_menu neighboring applications can be killed with two keystrokes (sort of clearance)
  • there are a lot of 'look and feel' options (incl. highlighting 'master' or 'dangerous' menus)
  • the options may be set at calling of e_menu and/or in [OPTIONS] section of a menu
  • parent menu options are inherited by child menu and can be overridden by its [OPTIONS]
  • for an easy exercise, git as well as fossil support of Geany IDE can be implemented with e_menu
  • encoding of menus is utf-8


Context action of Geany IDE

I try and show how the Geany context command can be used in all its beauty.

Imagine we have a Python module under testing in Geany. And it is called with parameters. And the parameters are changed from time to time.

Goings now and then to Run command setting are tiresome. And dull nuisance when we have that cool Geany context.

All we need is to write a multiline Python comment in our module (let it be module.py) containing something like:

  """ Begin of test block:
  module.py testpar1
  module.py testpar1 testpar2
  module.py testpar1 testpar2 testpar3
  etc.
  End of test block """

… and to set the context command equal to python3 %s

After that we select a line with current test parameters and call the context command from popup menu or with hotkey.

By this we get a batch of self-documented test cases directly inserted in the code!

By this we don't touch Run settings of other Python modules.


Introduction to e_menu

e_menu enhances the Geany context action allowing to have as much context commands as you want.

Now let's customize Tcl/Tk context help in Geany IDE. As a bonus you'll get a menu of commands to process selected texts of Geany IDE and even commands absolutely unrelated to Tcl/Tk, thus Geany and Tcl/Tk would help each other as declared.

Please try this:

1. If you do not have Tcl/Tk on your system, install it from www.tcl.tk. Linux users have it preinstalled, most likely. Though in Linux it may be necessary to install tklib, tcl-tls packages or even to update Tcl to 8.6 version. On Mac e_menu hasn't been tested.

2. Unpack the below attached zip to save:

  e_menu
  menus directory
  src directory

into some directory, e.g. /home/me/UTILS/e_menu (for Windows it may be C:\Users\me\UTILS\e_menu).

3. Go to Geany's menu 'Edit/Settings', then to 'Tools' page and enter in the 'Context action' field:

  wish /home/me/UTILS/e_menu/e_menu "s=%s"

Uff. Now you should be able to call the context help. While editing your Tcl/Tk script, select a Tcl/Tk command or simply place the caret on it and call “Context action” from popup menu. You should see something like:

where the first line calls Tcl/Tk help for “selection” (i.e. foreach, string, grid, panedwindow etc. - about 200 Tcl/Tk man pages and 26 pages of Tcl keywords from A.htm to Z.htm)

Other lines execute “selection” as an executable program by itself and by shell in console, with or without waiting their completion.

You can also attach a menu file to process your selected Geany text by external commands / programs. Of course, they may be absolutely unrelated to the Geany's selection, being called as you need them in Geany seance.

For example, you might desire to view a word in English-Russian (-Deutsch, -Hindi, -Arabic etc.) dictionary as above in the picture. You are just setting the caret on an English word and calling Geany's context to view its translation.

You can also make hierarchical menus as seen below:

The menu is rather simply organized and passed to e_menu as “m=menu.txt” parameter.


Calling e_menu

The command to call e_menu is following:

wish e_menu [s=%s] [m=menufile] [options]

where any parameter in brackets may be omitted, but one (or both) of s= or m= parameter must be present. If not, e_menu puts out a message with its synopsis and ends up.

s= parameter refers to Geany's selected text, though it may be anything else to process as 'selection'. If s= is set, e_menu's menu includes the following three commands:

  • HELP 'selection'
  • EXEC 'selection'
  • SHELL 'selection'

that mean:

  • HELP calls Tcl/Tk context help for 'selection'
  • EXEC executes 'selection' as a command/program by itself
  • SHELL executes 'selection' as a command/program in console box

m= parameter refers to a name of file containing a menu of commands. If m=menufile is set, e_menu adds to those three commands (if present) also the menufile commands.

If s= parameter is not set then the menufile commands only are present in the menu. If both s= and m= are set then all commands are present in the menu, i.e. HELP/EXEC/SHELL and the menu file commands.

You can always pass Geany's selection as s0= parameter and get rid of those abominable 'HELP/EXEC/SHELL' forever.

Other options of e_menu define a menu's look and behaviour and are described below, where:

  • number means integer value
  • “string” means text value

It's strongly recommended to quote “string option”.

options are:

OptionDescriptionUsage
N=number sets a number of menu application; numbers from 1 to 64 are used to close neighboring menus.N=65
“PD=directory” a work directory that can be used in commands as %PD wildcard “PD=/home/me/my projects/proj1”
“PN=project-name” a current project name that can be used in commands as %PN wildcard
(by default equals to a tailing part of working directory path or PD= if set)
“PN=myproj1”
fs=number size of fonts used in menu fs=9
“f1=font” name of font used in menu header “f1=Liberation Sans”
“f2=font” name of font used in menu entries “f2=Liberation Mono”
w=number width of menu items (in characters) w=30
c=number index of color scheme (0 through 12) c=1
o=number 'ornament' (view mode)o=0 - no header, no prompts shown
o=1 - header only shown (default)
o=2 - prompts only shown
o=3 - both prompts and header shown
bd=number sets a border width of menu itemsbd=0 - minimum
bd=1
b1=number sets an internal vertical padding of menu itemsb1=1
b2=number sets an internal horizontal padding of menu itemsb2=1
b3=number sets an external vertical padding of menu itemsb3=1
b4=number sets an external horizontal padding of menu itemsb4=1
t=1 sets a menu as a topmost window on screent=1
g=+x+y sets (x,y) screen coordinates of menu g=+700+200
wc=1 centers a menu on screenwc=1
“h=path” path to offline Tcl/Tk help"h=/home/me/DOC/www.tcl.tk/man/tcl8.6"
“b=browser” a browser to be used for viewing Tcl/Tk help (also used in a menu command ”%B link“)b=/usr/bin/epiphany
“u=string” value of string that is underscored“u=%s”
“qq=string” value of string with quotes (”) escaped“qq=%s”
“dd=string” value of string with special symbols (“, $, %, {}, [], <>, *) deleted and spaces converted to “_”“dd=%s”
“s0=string0”
“s1=string1”
-”-“-
“s9=string9”
- strings used in commands as %s0, %s1, …, %s9 wildcards“s0=%s” can be used when it's desirable to process Geany's selection without having those HELP/EXEC/SHELL commands in menu; other parameters (s1, …, s9) can contain environment variables or their combinations
“u0=string0”
“u1=string1”
-”-“-
“u9=string9”
the same as s0…s9 strings modified so that all spaces are converted to “_”“u1=%s-1st”
i0=number
i1=number
-”-“-
i9=number
define initial values for %i0, %i1, …, %i9 wildcards that mean counters of runs of corresponding commands; these wildcards are used both in commands and their menu names i1=100 i2=200
t0= .. t9= set formats of date/time that are used in commands containing %t0, %t1, %t2, %t3 .. %t9 wildcards:defaults are:
“t0=%H:%M:%S” - format of time
“t1=%Y-%m-%d” - format of date
“t2=%Y-%m-%d_%H:%M:%S” - format of date and time
“t3=%A” - format of day of week
t4= t5= .. t9= - after being defined they can be used as %t4..%t9 wildcards in commands
“ed=editor” sets an editor path (Geany's default)“ed=C:/Program Files (x86)/Notepad++/notepad++.exe”

Though not recommended, it may be desirable when you should edit files external to your current project.

Also, it would be in use if your Geany had been installed into some unusual directory, e.g. /home/me/Geany_Forever or in C:\GEANY_FOREVER

In any case it can be got over by some substitution like “z=editor” at e_menu call and %z file.txt in a command.
“a0=Tcl command(s)” sets Tcl command(s) to be run at start of e_menu before any processing of other parameters (m= including, that may be potentially buggy)“a0=D starting e_menu”
“a1=Tcl command(s)” sets Tcl command(s) to be run at start of e_menu before processing a=list (see below)“a1=wm attributes . -alpha 0.8”
a=list sets a list of hotkeys of autorun menu items to be run at start of e_menua=1,8,b
ah=list sets a list of hotkeys of autorun menu items of [HIDDEN] section to be run at start of e_menuah=1,2,3
“a2=Tcl command(s)” sets Tcl command(s) to be run at start of e_menu after processing a=list (see above)“a2=d {Hello! \n\n Today is [clock format [set systime [clock seconds]] -format {%A %d-%m-%Y %H:%M}] \n\n Current dir: [pwd]}“
P=syms sets a symbol(s) used instead of ”%” in the e_menu callIt's important if the caller of e_menu (Geany, shell) uses % literals conflicting with e_menu's parameters.
Example of overcoming Geany's %d substitution:
wish e_menu “s=%s” P=# “t2=#A #d-#m-#Y #H:#M”
pa=number sets a pause (in milliseconds) to suspend e_menu before starting it; sometimes it may be desirablepa=500
“x*=string” e_menu wildcard %x* of commands“x=%s” “x0=%s” “xz=%s”
“y*=string” e_menu wildcard %y* of commands“y=%s” “y0=%s” “yz=%s”
“z*=string” e_menu wildcard %z* of commands“z=%s” “z0=%s” “zz=%s”
“d=string” reserved for Geany's wildcard %d“d=%d”
“e=string” reserved for Geany's wildcard %e“e=%e”
“f=string” reserved for Geany's wildcard %f“f=%f”
“l=string” reserved for Geany's wildcard %l“l=%l”
“p=string” reserved for Geany's wildcard %p“p=%p”
“om=0” om=0 overrides the [OPTIONS] menu options
(by default [OPTIONS] options overcome the options defined in the call string of e_menu)
om=0

Note: options s0..s9, u0..u9, x*, y*, z* can include wildcards used in menu commands, e.g.:

  "s0= run #%i0 at %t2"
  "u0=_run_#%i0_at_%t2"

See also “Processing wildcards” below.


Setting options in a menu file

Most options of a call string can be set in [OPTIONS] section of a menu file, e.g. :

  R:  R: 6
  R: Firefox search for "%s" R: firefox -search "%s"
  R: Wikipedia for "%s" R:%B https://en.wikipedia.org/w/index.php?cirrusUserTesting=classic-explorer-i&search=%+
  R: Open/create file(s) "%s" R:%E %s
  R: geany: edit all          R: geany readme.md wiki.txt e_help.tcl e_menu.tcl
  
  R:  R: 6
  MW: Git  MW: m=%PN/git.mnu "u=%s" o=0 w=50
  MW: Tcl/Tk    MW: m=%PN/tcltk.mnu w=20
  MW: Python    MW: m=%PN/python.mnu w=40
  MW: Utils     MW: m=%PN/utils.mnu
  MW: Links     MW: m=%PN/links.mnu
  
  [HIDDEN]
  R: 1. Stop work R: ?-33*60?-7*60:ah=2? audacious  /home/me/PG/breakon.wav
  R: 2. Arbeiten  R: audacious /home/me/PG/breakoff.wav
  
  [OPTIONS]
  om=1
  o=0
  c=0
  fs=11
  bd=1
  w=52
  h=/home/apl/DOC/www.tcl.tk/man/tcl8.6
  PD=/home/apl/PG/Tcl-Tk/projects/e_menu
  b=/usr/bin/chromium

The om= option is of particular weight. By default, the menu [OPTIONS] take priority over the options defined in a call string. This can be overridden by setting om=0 in the call string of e_menu - after that the call string options would have more priority than the menu [OPTIONS]. But all the same, the final decision is left to the menu that can reset the om= option to om=1 and override all previously set options of the call string or the parent menus.

Some options are intended mostly for e_menu call string than for [OPTIONS] section. E.g. if you want to have a menu system 'project sensitive', do not include into [OPTIONS] such options as PD= (project directory) and PN= (project name). They are mostly for setting in a command line to call e_menu.

And vice versa, if you want to have a specific menu iron bound to some project, include into its [OPTIONS] the PD=, PN= and om=1.


Examples

Here are two examples of calling e_menu.

1.

  wish /home/me/e_menu/e_menu "s=%s" "m=menus/menu.mnu" \
    "h=/home/me/DOC/Tcl/tcl8.6" c=1 fs=11 \
    "PD=/home/me/PG/projects/e_menu" b=/usr/bin/epiphany a=6,b

- this call of e_menu consists of:

  • selected text of Geany IDE editor (%s)
  • menu file named menus/menu.mnu
  • color scheme 1
  • font size 11
  • working directory /home/me/PG/projects/e_menu
    (this would set PN=e_menu as 'project name', used as %PN wildcard in commands)
  • browser epiphany
  • two menu items to run at start with hotkeys '6' and 'b'

Notice that Tcl/Tk help is offline and located in /home/me/DOC/Tcl/tcl8.6. Also it's worth noticing that menu.mnu file is located in menus subdirectory of e_menu not related anyhow to the /PD=/ directory which is a separate option of call and used as %PD wildcard in menu commands.

2.

Here is an example of bash file that runs Geany IDE and three menu applications positioned at right side of screen:

  #! /bin/bash
  
  # run Geany with e_menu project files
  PROJECT=e_menu
  THEME="Preparing wiki.txt"
  SUBJ=" - calling e_menu"
  
  DIR=/home/apl/PG/Tcl-Tk/projects/e_menu
  BROWSER=/usr/bin/epiphany
  LEFT=+1462
  
  curdir=$PWD
  cd $DIR
  
  wish ./e_menu "s0=$PROJECT" "s1=$THEME" "s2=$SUBJ" "b=$BROWSER" "PD=$DIR" \
    m=menus/git.mnu g=$LEFT+30 t=1 o=0 w=21 fs=10 pa=100 &
  
  wish ./e_menu "b=$BROWSER" "PD=$DIR" \
    m=menus/wiki.mnu g=$LEFT+465 t=1 o=0 w=21 fs=10 pa=100 &
  
  wish ./e_menu "b=$BROWSER" "PD=$DIR" \
    m=menus/templates.mnu g=$LEFT+808 t=1 o=0 w=21 fs=10 pa=100 a=1 &
  
  geany readme.md wiki.txt e_help.tcl e_menu.tcl &
  
  cd $curdir

Notice that all three menus are called as topmost independent applications (t=1, &) without 'ornament' (o=0), the last menu running 1st item at start (tkcon to be exact). Geany IDE is run with project files as passed parameters. This would result in the picture shown somewhere below. All menus share some options defined with environment variables (BROWSER, DIR, LEFT) while others (PROJECT, THEME, SUBJ) are supplied to git.mnu only for use in git commands as %s0, %s1 and %s2 wildcards.


Creating e_menu files


Structure of menu

Common structure of menu file is following:

  <marker> name1 <marker> command1
  <marker> name2 <marker> command2
  
  <marker> name31 <marker> ? command31
  <marker> name32 <marker> ?interval? command32
  
  <marker> name4 <marker> command4
  <marker> name4 <marker> command4 continued
  <marker> name4 <marker> command4 continued
  
  # comments
  # ...
  
  [HIDDEN]
  <marker> name5 <marker> command5
  <marker> name6 <marker> command6
  # ...
  
  [OPTIONS]
  # ... options of e_menu call string
  # ...

where <marker> can be one of following:

  • R/
  • R: these ones run command while e_menu continues working
  • RE/
  • RE: these ones execute command while e_menu exits
  • RW/
  • RW: these ones run command while e_menu waits its completion
  • S/
  • S: these ones run command in console box while e_menu continues working
  • SE/
  • SE: these ones execute command in console box while e_menu exits
  • SW/
  • SW: these ones run command in console box while e_menu waits its completion
  • M/
  • M: these ones call a child menu and a parent continues working
  • MW/
  • MW: these ones call a child menu and a parent waits its closing
  • ME/
  • ME: these ones call a child menu and close a parent
  • I: Tcl commands (incl. the internal e_menu functions D, Q, S)

Markers with ”/“ are the same as with ”:“; the one and only difference is that in their corresponding commands all “\” are converted to ”/“. It's only for use in Windows and only for convenience.

In fact you can write Windows' pathnames using ”/“ instead of “\”, because e_menu being written in Tcl recognizes only ”/“ as a dividing slash.

Normally commands are run without catching their errors or warnings. But if you want to see return messages of a command, you may set ”?“ before the command as in command31 above. Also, you can run a command repeatedly with interval in seconds set as ?interval? before the command (see command32 above).

A menu item can contain several commands to run. To enable this you should place them under the same item name in successive lines. There must be strongly equal names for e_menu to identify them as a batch of commands united under a menu item. Any differences including spaces and empty lines are treated as a begin of new command or comment.

  In Geany editor, pressing Ctrl+D doubles a current line or selected text.

For example command4 (see above) contains in fact three successive commands united under ” name4 “.

To make it comfortable, you can use as comments the numeration of menu items, e.g.:

  1.
      R/ GoldenDict R/ "C:\Program Files (x86)\GoldenDict\GoldenDict.exe" en "%s"
  2.
      RW/ FVdict for "%s" RW/ cd C:\Program Files (x86)\FVdict
      RW/ FVdict for "%s" RW/ fvdict.exe %s
  3.
      R/ Firefox search for "%s" R/ "C:\Program Files\Firefox\firefox.exe" -search "%s"

[HIDDEN] section of menu file is of the same format as the previous ('visible') one. Now it is used only to autorun commands that aren't visible in menu. For example command5 and command6 (see above) can be run at start of e_menu with ah=1,2 call parameter. Hidden items are numerated with 1,2,..,9,a,b,… as well as visible ones.

One important command used in a batch of commands is 'cd'. It is inevitable if you have some program that, being altogether useful and good, nevertheless innocently assumes a current directory to be its 'own' one.

Comments are lines that begin with anything different from <marker>. Use for comments any commenting symbols you like.

A menu item name can begin with F1 through F12 which means a hotkey F1…F12 for this name. By default, items have hotkeys 1 through 9 and a through z. For example:

  RE: F1 Geany's help RE:%B file:///usr/share/doc/geany/html/index.html

- this would display e_menu that would display (after second F1) the help of Geany IDE and close.

It's useful feature if you mapped F1 to Geany context action - then double pressing F1 brings up Geany's help and closes e_menu.

An item marked with I: refers to some internals, namely the direct execution of Tcl commands. D, Q, S procedures of e_menu can be also used in I: items. Here a few examples:

  I: Xterm in "%PD" I: D run bash in %PD; if {[Q "BASH" "Want to bash?"]} {cd "%PD"; S bash}
  
  I: Xterm in "%PD" (mute) I: cd "%PD"; S bash
  
  I: Console commands I: S dir \n echo \$PWD \n date

where $ escaped as \$, CLI commands devided with \n.


Wildcards in menu names and commands

Item names and commands can include the following wildcards:

WildcardDescription
%s Geany's selected text
%u Geany's selected text underscored
%+ Geany's selected text with ” “ converted to ”+“
%PD a directory passed as PD= parameter to e_menu
%PN a directory passed as PN= parameter to e_menu
%w a working (current) directory
%m a directory of e_menu
%t0 a system time
%t1 a system date
%t2 a system date + time
%t3 a system day of week
%qq qq= parameter of e_menu
%dd dd= parameter of e_menu
%s0
%s1
-”-“-
%s9
s0= parameter of e_menu
s1= parameter of e_menu
-”-“-
s9= parameter of e_menu
%u0
%u1
-”-“-
%u9
u0= parameter of e_menu
u1= parameter of e_menu
-”-“-
u9= parameter of e_menu
%i0
%i1
-”-“-
%i9
0th counter of runs (it may be initialized with i0= parameter of e_menu)
1st counter of runs (it may be initialized with i1= parameter of e_menu)
-”-“-
9th counter of runs (it may be initialized with i9= parameter of e_menu)
%B “link” calls a browser with passed link; here %B corresponds to b= parameter of e_menu
%Q “title” “message” puts out a query with title and message asking “OK” or “Cancel”; if answered “Cancel”, cancels next commands of batch
%E file1 [file2 …] calls Geany editor to edit/create file(s) e.g.:
… to edit file(s) of Geany's selection:
%E %s
… to edit/create all files of project by one click:
%E mod1.c mod2.c mod3.c mod4.c mod1.h mod2.h mod3.h mod4.h etc.
%% % symbol
%d Geany's wildcard %d (reserved)
%e Geany's wildcard %e (reserved)
%f Geany's wildcard %f (reserved)
%l Geany's wildcard %l (reserved)
%p Geany's wildcard %p (reserved)


Processing wildcards

Wildcards of names and commands are processed in the following order:

  • %PD
  • %PN
  • %s0, %s1, …, %s9
  • %u0, %u1, …, %u9
  • %+
  • %qq
  • %dd
  • %w, %m
  • %s
  • %u
  • %t0, %t1, %t2, %t3
  • %i0, %i1, …, %i9

Wildcards %s0 … %s9 … %u0 … %u9 can delegate their values to lower levels (from %s0 down %u9).

For example:

  "s1= %s committed #%i1 at %t2" "u1=%s1"
  
      is equivalent to:
  
  "s1= %s committed #%i1 at %t2" "u1=_%s_committed_#%i1_at_%t2"

In some cases, it may be desirable to have an hierarchy of substitutions.

For example:

  "s1= Theme 1" "s2=%s1.2" "s3=%s2.3" "s4=%s3.4"
  
      is equivalent to:
  
  "s1= Theme 1" "s2= Theme 1.2" "s3= Theme 1.2.3" "s4= Theme 1.2.3.4"


Examples

1.

e_menu being written in Tcl requires ”/“ in pathnames. So, in order to avoid manual converting “\” to ”/“, items are marked with “R/” instead of “R:”, “RW/” instead of “RW:” and so on. It's used only in Windows.

Here is an example:

  # menu for e_menu
  
   R/ GoldenDict              R/ "C:\Program Files (x86)\GoldenDict\GoldenDict.exe"
   R/ FVdict for "%s"         R/ cd C:\Program Files (x86)\FVdict
  RW/ FVdict for "%s"        RW/ fvdict.exe %s
   R/ Wish "samples/%s.tcl"   R/ wish "C:\PG\Tcl-Tk\examples\Proj01\%s"
   S/ Tkcon                   S/ tkcon
  
   R: Firefox search for "%s" R: firefox -search "%s"
   R: Wikipedia for "%s"      R: %B https://en.wikipedia.org/w/index.php?cirrusUserTesting=classic-explorer-i&search=%+
  
  MW/ Git menu               MW/ "m=menus\gitmenu.txt" o=0 "PD=%d" "s=%s"

A menu item FVdict for ”%s“ consists of two commands: the first one sets current directory of command, the second executes it (and wait its completion).

Notice that the command 'cd' does not require quoting directory path, because it's executed by e_menu that adds missing quotes. Other commands with spaced pathnames need to quote them.

Also notice how WWW searches are called - one for Firefox search machine and one for Wikipedia search. Both use the Geany's selected text (%s, %+).

A last item calls and then waits for a git menu that is in the example below.

2.

All commands in this menu need changing to work directory, so 'cd' is first used in a batch of commands.

The command batches contain mixed 'R' and 'S' markers which means that their commands are executed by itself and by shell in console box.

The wildcard %s refers to Geany's selection. The wildcard %dd is the same as %s but it's used to get rid of special symbols as ”, $, %, {, }, [, ], <, >, *.

The wildcard %Q is a query with 'title' and 'query text'. Being answered 'Cancel' it cancels the execution of batch.

In %Q command you should use edging double quotes and internal single quotes in a title and a message. Symbol \n stands for an empty line.

  # git menu for e_menu
  
  R:git status R: cd %PD
  S:git status S: git status
  
  R:git gui R: cd %PD
  R:git gui R: git gui
  
  R:git add * R: cd %PD
  S:git add * S: git add * 
  
  R:git commit -m "%dd" R: %Q "Committing changes" "Commit with message\n\n'%dd' ?"
  R:git commit -m "%dd" R: cd %PD
  S:git commit -m "%dd" S: git commit -m "%dd"
  
  R:git commit -am "%s" R: %Q "Committing changes" "Add and commit with message\n\n'%s' ?"
  R:git commit -am "%s" R: cd %PD
  S:git commit -am "%s" S: git commit -am "%s"
  
  R:git log "--since=1 day ago" R: cd %PD
  S:git log "--since=1 day ago" S: git log "--since=1 day ago"
  
  R:git log -p "--since=1 day ago" R: cd %PD
  S:git log -p "--since=1 day ago" S: git log -p "--since=1 day ago"
  
  MW: Others MW: m=menus/git2.mnu w=40


Using e_menu

e_menu usage is rather standard for menus. The following keys take actions of menu:

  • Down or Tab to select a next item
  • Up or Shift+Tab to select a previous item
  • Space, Enter, Return to execute a selected item
  • hotkeys 1,2,3..a,b.. to execute items quickly
  • hotkeys F1, F2, .. F12 (if set) to execute items quickly
  • Escape to close a menu

The following keys can be also used:

  • Ctrl+T to switch on/off 'stay on the top' mode
  • Ctrl+E to edit a current menu file in Geany IDE
  • Ctrl+R to re-read a current menu file and restart its 'autorun' list
  • Ctrl+D (or mouse right click) to delete other e_menu applications (type of clearance)
  • Ctrl+Right to increase a menu width
  • Ctrl+Left to decrease a menu width

If not redefined in the menu F1 calls this wiki page.

You can use the right and the left arrow keys for calling and closing a submenu respectively.


Detailed example

The following example illustrates step by step how to create and use e_menu in Windows. Linux version is mostly the same and even more simple than Windows'. There are only two resulting Linux screenshots below.


Step 1. Initial testing.

It's assumed that you had installed Tcl/Tk and e_menu software. Also you had to customize the Geany context action. If not, refer to 'Introduction to e_menu' section above.

It's also assumed in the next sections that e_menu has been unpacked into C:\UTILS\e_menu directory.

Try e_menu now. Set the caret on a word of your text edited in Geany IDE. You may also select a piece of text. Call 'Context action' from popup menu or with a hotkey mapped to it.

You should see the following:

(in this example 'Step 1' was selected in Geany editor).

If you see it, e_menu works OK. Well, if you are not Tcler then skipping the rest of this step would not harm you badly.

The first line of the picture above means calling a context help on Tcl/Tk command or keyword you had selected.

The help is online. You can tune it to be offline for faster response and zero of internet. To do it try this:

  • include the h= parameter into Geany context action:
  wish C:\UTILS\e_menu\e_menu "s=%s" h=C:\DOC\www.tcl.tk\man\tcl8.6
  • download the Tcl/Tk help to C:\DOC directory with commands:
  md C:\DOC
  
  cd C:\DOC
  
  wget -r -k -l 2 -p --accept-regex=.+/man/tcl8\.6.+ https://www.tcl.tk/man/tcl8.6/

Now the offline help should be ready to call. If not, check the version of your wget utility.

Retry Tcl/Tk help calling. Select in your text (or place the caret on), for example, package and call Geany's context action. You should see something like:

Click on the first item and you would see the Tcl/Tk help on package.


Step 2. Creating a menu.

Let's try and create a simple menu of 2 commands that would be available from Geany's context.

The menu file will be C:\UTILS\e_menu\menus\test1.mnu. We shall use commands that process Geany's selected text to:

  • seek the selected internet pages
  • view the selected words in a dictionary

Fill the C:\UTILS\e_menu\menus\test1.mnu with the following:

  R/ Firefox search for "%s" R/ ""C:\Program Files (x86)\Mozilla Firefox\firefox.exe" -search "%s"
  
  RW/ Dictionary FVdict for "%s" RW/ cd C:\Program Files (x86)\FVdict
  RW/ Dictionary FVdict for "%s" RW/ fvdict.exe %s

(Here a fvdict dictionary is used. It's one of many similar dictionaries that accept a word as input parameter and put out a translation of it. This one is English-Russian available at http://aplsimple.ucoz.ru).

After that include the menu file into the call string of Geany's context, for example:

  wish C:\UTILS\e_menu\e_menu "s=%s" h=C:\DOC\www.tcl.tk\man\tcl8.6 m=menus/test1.mnu

NOTE: if you dislike to have the HELP/EXEC/SHELL commands in your menu though the context would be desirable, you can use:

  • “s0=%s” instead of “s=%s” in Geany's context command
  • %s0 instead of %s in menu commands

For example, you can write Geany's context command as:

  wish C:\UTILS\e_menu\e_menu "s0=%s" m=menus/test1.mnu

… and test1.mnu as:

  R/ Firefox search for "%s0" R/ "C:\Program Files (x86)\Mozilla Firefox\firefox.exe" -search "%s0"
  
  RW/ Dictionary FVdict for "%s0" RW/ cd C:\Program Files (x86)\FVdict
  RW/ Dictionary FVdict for "%s0" RW/ fvdict.exe %s0

… and then you should see:

… instead of:

Try and seek the selected “Firefox” in WWW. Click the item named Firefox search for “Firefox” and you would see something like:


Step 3. Creating a submenu.

The e_menu's menus are hierarchical. You can include a submenu into any menu with the following e.g.:

  MW/ Test2 menu MW/ "m=menus\test2.mnu" o=0

NOTE: here “o=0” option means that the submenu doesn't contain the header i.e. those awful messages “Use arrow… (or press…”. Also notice that s0= option is passed to the submenu (as well as the other options of parent menu), and only o= option was overridden for the child menu. In the example below the PD= option is added as well. The header is useful for mouse moving of menu, btw.

Let's create a submenu test2.mnu located at C:\UTILS\e_menu\menus.

However, at the beginning we should write it in the parent menu test1.mnu so:

  • test1.mnu:
  R/ Firefox search for "%s0" R/ "C:\Program Files (x86)\Mozilla Firefox\firefox.exe" -search "%s0"
  
  RW/ Dictionary FVdict for "%s0" RW/ cd C:\Program Files (x86)\FVdict
  RW/ Dictionary FVdict for "%s0" RW/ fvdict.exe %s0
  
  MW/ Test2 menu MW/ "m=menus\test2.mnu" "PD=C:\UTILS\e_menu\" o=0

After that if you clicked on the menu item, e_menu would offer to create the menu file in Geany IDE. Answer “OK” and you'll get the following menu template:

   R: nam1  R: prog
  
   S: nam2  S: comm
  
  MW: nam3  MW: m=e_menu/nam3.mnu

The template contains three most common types of records to fill a menu.

Now let's fill our submenu with the following:

  • test2.mnu:
  SW: echo %%s0 is %s0 SW: echo %%s0 is %s0
  
  SW: echo %%PD is %PD SW: echo %%PD is %PD
  
  R: git init R: %Q "Init GIT" "Are you sure to init git in\n\n%PD ?"
  R: git init R: cd %PD
  S: git init S: git init
  
  R: git status R: cd %PD
  S: git status S: git status
  
  R: git gui R: cd %PD
  R: git gui R: git gui
  
  R: git add * R: cd %PD
  S: git add * S: git add * 
  
  R: git commit -am '%s0' R: %Q "Committing changes" "Do you really want to commit with message\n'%s0' ?"
  R: git commit -am '%s0' R: cd %PD
  S: git commit -am '%s0' S: git commit -am "%s0"

Call the Geany context action again. You should see the following:

After choosing “Test2 menu” you should see the following:

In the submenu you can play with its items. Notice that some git commands would require a confirmation. Also notice how a working directory is passed to the child menu with “PD=%” parameter and then used in its commands as “%PD” wildcard.

First items only echo the options passed to e_menu. Echos are useful for debugging btw. Other items refer to GIT system so that they would be working if you had installed GIT.


Usage in Linux

Actually all previous considerations apply also to Linux usage of e_menu. Therefore, two Linux screenshot only are given here.





Tips and hints


What's all those R, RE, RW, S, SE, SW, M, ME, MW mean?

R stands for run a program by itself

S stands for run a command by shell in console

M stands for call a menu

E stands for exit after calling action

W stands for wait for completion of action


Changing menus' look and feel

Let me remind you how e_menu is called:

  wish /home/me/UTILS/e_menu/e_menu "s=%s" [options]

The following call options of e_menu can influence on menus' look and feel:

  • o=0 - turns off all of 'ornament' leaving a menu naked (minimalistic)
  • o=1 - turns on only a header of menu (default)
  • o=2 - turns on only prompts in menu items (RUN, EXEC, SHELL, MENU)
  • o=3 - turns on all of 'ornament'
  • fs=12 - sets a font size of menu's header and items equal to 12
  • “f1=Sans” - sets a font name of header to “Sans”
  • “f2=Mono” - sets a font name of items to “Mono”
  • w=40 - sets a width of menu buttons (in characters); 40 is default
  • wi=40 - sets a position of the arrow icon (it's for Windows esp.)
  • g=+100+200 - positions a menu at x=100, y=200 coordinates of screen
  • t=1 - sets a menu as topmost over other windows on desktop
  • c=0 - sets an index of color scheme; 0 is default.

The following colors are available from c=0 to c=12:

and their shadowed counterparts (3rd scheme is of special highlight as you see):

5th color scheme can be used to open a potentially dangerous menu, e.g. containing some irrevocable commands.

The dangerous and irrevocable commands may be collected under a red menu as big as a monitor screen, e.g.:

Before their call, you can set a terrible warning, sort of:

You can use a special form of menu item name to set a separator, namely:

  R:    R: N
  
     or
  
  R: -- R: N

where N sets a vertical size of separator. If the item name contains “-” symbol(s) it means a visible separator, otherwise it sets a separating blank space.


Warnings of menus

Using a1= call parameter, you can warn a user about potential risks of an open menu, e.g.:

  MW: Dangerous MW: m=menus/git2.mnu w= bd=7 fs=50 c=5 "a1=if {![Q \"DANGER!\" \"These commands are dangerous\nand can set the world on fire!\n\nContinue?\"]} exit"

Here the Tcl commands are used to exit and close the dangerous menu possibly open by mistake. Q is a query with “head” and “message” that can contain the above mentioned wildcards. Q returns 'false' if answered 'Cancel' so that 'exit' Tcl command closes the menu.

When calling a menu item, you can use %Q “head” “message” in a command batch. It's the same query with the difference that e_menu stops the batch of commands after answering 'Cancel'. For example:

  R:git reset --hard HEAD R: %Q "RESET" "This cancels the last uncommitted changes and resets to the last commited state!\n\nDo you want to RESET ?\n\n(VERY LIKELY IT'S CANNOT BE UNDONE)"
  R:git reset --hard HEAD R: cd %PD
  S:git reset --hard HEAD S: git reset --hard HEAD

- here the cancelled commands are 'cd' and 'git reset'.


Counting and timing commands

You can include into menu commands (and, as recommended, into corresponding item titles) the following wildcards:

  • %t0 is a system time
  • %t1 is a system date
  • %t2 is a system date + time
  • %t3 is a system day of week
  • %i0
  • %i1
  • %i9 - are counters of item runs

It's useful feature for commands that are logging or marking their data (files, directories etc.) with a current time, date and/or counter. There are 10 run counters per a menu and 10 time/date formats that can be set at call.

Here is a typical example:

  git commit --amend -am "%s: amending N%i0 made at %t2"

- this git command would amend a last commit with a message sort of

  "My_function_of_all: amending N3 made at 2018-03-31_14:15:07"


Running commands at start

It's rather useful feature of e_menu allowing at start of a menu:

  • to run any runnable item(s)
  • to call any submenu(s)
  • to run hidden command(s) or program(s)

Thus you can organize a menu system so there would be a starting menu that in turn would run and call all the rest (menus as well as commands).

Then, if you would desire to destroy and/or re-run the 'autorun' suite of menus, you may press Ctrl+D and/or Ctrl+R on the 'master' menu.

The master menu could be colored in 3rd color scheme that would distinguish it among others. 3rd color scheme menus aren't shadowed even while losing a focus. And of course e_menu being open source allows you to change and expand its color schemes list (see e_menu.tcl).

See above 'Calling a menu' section, options a=, ah=. Also 'Creating a menu' section describes how to include hidden commands into a menu.

Here is my fresh experience when this feature had fired. In Windows, of course.

I had a startup batch file with the following lines (ornaments omitted):

  cd %DIR%
  start wish %EMDIR%/e_menu "m=menus/gitmenu.mnu"
  start wish %EMDIR%/e_menu "m=menus/menu.mnu"
  start cmd.exe /c "C:\Program Files (x86)\Geany\bin\geany.exe" readme.md wiki.txt e_help.tcl e_menu.tcl

The problem was the last line. I was probing and reprobing these ones:

  1. start cmd.exe /c "C:\Program Files (x86)\Geany\bin\geany.exe" readme.md wiki.txt e_help.tcl e_menu.tcl
  2. start "C:\Program Files (x86)\Geany\bin\geany.exe"            readme.md wiki.txt e_help.tcl e_menu.tcl
  3. start "C:\\Program Files\ (x86)\\Geany\\bin\geany.exe"        readme.md wiki.txt e_help.tcl e_menu.tcl
  4. start "C:/Program Files (x86)/Geany/bin/geany.exe"            readme.md wiki.txt e_help.tcl e_menu.tcl
  5. start /D "C:\Program Files (x86)\Geany\bin" geany.exe         readme.md wiki.txt e_help.tcl e_menu.tcl
  6. start /D "C:\Program Files (x86)\Geany\bin" geany.exe %DIR%/readme.md %DIR%\wiki.txt %DIR%\e_help.tcl %DIR%\e_menu.tcl

1st case was OK excluding those troublesome traces of cmd.exe.
2nd, 3rd, 4th had failed at all. If Windows had forbidden it, he might bark at me with words I don't know. But no words neither Geany seen :()
5th was OK but files (readme.md etc.) had been open as new ones (in C:\Program Files (x86)\Geany\bin)
6th was OK but my working directory had been changed to C:\Program Files (x86)\Geany\bin. Not to say about those repeating %DIR%. S… again!

And only after browsing WWW the problem was resolved with the 7th line ('start' accepts optional “header” … or accepts not in case of cmd.exe):

  7. start "" /b "C:\Program Files (x86)\Geany\bin\geany.exe" readme.md wiki.txt e_help.tcl e_menu.tcl

Uff, stupid, what titanic efforts you have taken while all you need is your own e_menu's starting features. Do so:

Insert into “menus/menu.mnu” the following line (it will be useful by itself in future):

  R: Open all R: %E readme.md wiki.txt e_help.tcl e_menu.tcl

… and assuming that “Open all” entry is number 8 in menu.mnu, change its call so:

  start wish %EMDIR%/e_menu "m=menus/menu.mnu" a=8

That's all. Minus a special start of Geany in batch file. Plus a useful menu command that allows to restore your project file list in Geany IDE.


Starting menu items at intervals

You can also write a menu item so that it would be started periodically with an interval set in seconds.

Common usage is following:

  <marker> name1 <marker> ?interval? command1
  <marker> name1 <marker> command1 continued

where <marker> is R:, R/, S: or S/. Markers with E ('run and exit') and W ('run and wait') aren't badly reasonable. Maybe S: and S/ too. But R: and R/ is the point.

Examples:

  R: Run periodic logging at 10 min. interval R: ?10*60? cd %PD
  R: Run periodic logging at 10 min. interval R: logging
  
  R: Run periodic archiving at 1 hour interval R: ?60*60? cd %PD
  R: Run periodic archiving at 1 hour interval R: archiving
  
  R: Run periodic messaging at 2 hour interval R: ?2*60*60? messaging
  
  R: Run periodic reminding of rest at 45 min interval R: ?-45*60/-15*60? stopwork_arbeiten %TI

The last task should be explained in details. The common format of periodic command is following:

  ?NSEC/NSEC1:a=n1,n2/NSEC2:ah=n3,n4/.../TN=X:ah=n5/? TASK_COMMAND %TI

where:

  • NSEC - interval in seconds to run TASK_COMMAND:
    • if NSEC>0, TASK_COMMAND is executed immediately and then after NSEC seconds
    • if NSEC<0, TASK_COMMAND is executed after abs(NSEC) seconds
  • NSEC1, NSEC2 have the same meaning, but apply to a= (autorun list of commands) and ah= (autorun list of hidden commands)
  • if a= and ah= are not present, the current command is called
  • TN=X:ah=n5 means “after X cycles execute ah=n5 and stop”
  • %TN is a wildcard that equals to the current cycle number
  • %TI is a wildcard that equals to the current position in batch (while NSEC TI=0, while NSEC1 TI=1, while NSEC2 TI=2)

So the batch

   ?-45*60/-15*60? stopwork_arbeiten %TI

means:

  • wait 45 minutes
  • run “stopwork_arbeiten 0”
  • wait 15 minutes
  • run “stopwork_arbeiten 1”
  • repeat all

We could easily set the task of theater show:

  S: Comedy 'Miaou' S: ?-0.1/-20:a=/TN=3:ah=3/-0:ah=1/-10:ah=2/-3:ah=2/-3:a=? echo 'Miaou' part %TN \ndate
  [HIDDEN]
  S: Intermission S: echo Intermission %TN \ndate
  S: Bell S: echo Bell N %TI-3 \ndate
  S: Curtain S: echo Curtain \ndate

which means:

  • comedy part 1 starts
  • 20 seconds of part 1 showing
  • intermission 1 starts
  • 10 seconds of intermissing
  • bell #1
  • 3 seconds of intermissing
  • bell #2
  • 3 seconds of intermissing
  • comedy part 2 starts
  • 20 seconds of part 2 showing
  • intermission 2 starts
  • 10 seconds of intermissing
  • bell #1
  • 3 seconds of intermissing
  • bell #2
  • 3 seconds of intermissing
  • comedy part 3 starts
  • 20 seconds of part 3 showing
  • curtain

Here is the show and even a spectator:)

You may desire to stop this periodical stuff manually. Just call it again and e_menu would stop it on your confirmation.


Making menus 'project sensitive'

e_menu uses a tail of working directory path as 'project name'.

E.g. if you started a project like that:

  cd /home/me/PG/projects/my_best_project
  wish /home/me/UTILS/e_menu ... (run common menus)
  geany ...                     (run Geany IDE)

then 'my_best_project' will be 'project name'.

This name can be used as %PN wildcard in the calling string of e_menu as well as in the menu commands.

  Note: you should use %%PN instead of %PN in Windows' command line.

So, you can have a lot of menus in “%PN” subdirectory of e_menu that are specific for your current project and the one and only Geany context command for all projects like that:

  wish /home/me/UTILS/e_menu "s=%s" "m=%PN/main.mnu" ...

It would open the main menu of your current project as Geany's context command.

Also you can set in the calling string of e_menu “PN=projectname” parameter that would override a value of %PN wildcard taken from a working directory. It may be suitable when your different projects are named equally (e.g. /…/Java/Project1 and /…/JavaScript/Project1).

The environment variable E_MENU_PN has the highest priority in setting the project name. E.g., in Linux you can call e_menu this way:

  export E_MENU_PN=myproject
  wish /home/me/UTILS/e_menu "s=%s" "m=%PN/main.mnu" ...

It would be convenient to have a batch of common menus that are not related to Geany's context and are called just before starting Geany IDE. Using g=+X+Y (geometry) and t=1 (stay on top) parameters you can dispose the common menus at left or right side of screen to have them at hand. And while coding in Geany IDE, you are free to use a project specific menu bound to Geany context command.


Closing all menus

Sometimes you might desire to close all e_menu applications. To do this, press Ctrl+D keys or click a menu with a mouse right button.

A query would occur asking you to confirm closing all menus. Press OK to close all of them. A current menu ('menu destroyer') should close all e_menu applications excepting itself.

You can control this behaviour with assigning 'id' to menus by N=id (id=1..64) option of call. A menu destroyer normally doesn't kill a menu if its 'id' is greater than 64 (e.g. N=65 passed). Also it doesn't kill itself, if it is a parent and has a g= (geometry) option passed.

There are not so much reasons, e.g., to call e_menu from Geany IDE with geometry (g=) passed.

However, it's worth noticing that this feature is buggy under Linux and generally doesn't work under Windows.


Sort of debugging

Normally no error messages are displayed while e_menu running commands. There are many useful programs that return some warning mess as if it were errors. This unnecessary trash is thrown off by e_menu.

However, sometimes you need those error messages. E.g. you wrote a menu item that doesn't work stubbornly and is silent at that. What's up? In such case you can get over the silence of e_menu with setting “?” before a command, for example:

  R: it doesn't run R: ? this_is_not_runnable

- this would run this_is_not_runnable and display its return (error) message.

If your calling e_menu fails at start, you can call it in console so that you would see its error messages. You can use also a0=, a1=, a2= parameters to check if your starting list (a=) is run properly. See above “Calling e_menu” section.

A command useful for debugging is a console echo if properly included in a menu, e.g.:

  S: Echo: %%s1  S: echo %s1

D and S commands can be used in a0=, a1=, a2= parameters to show messages and run commands in console, e.g.:

  "a0=D starting e_menu" "a1=D start inits" "a2=D end of inits"


Issues

Although being simple and humble, e_menu isn't totally faultless and ideal as all in the world. As my Geany too, alas.

Regretfully, there are some issues with Geany's passing of selected text to its context command.

E.g. there is a problem of calling the context action in Windows version of Geany, namely a hotkey doesn't work if you select something more complex than just Latin letters (e.g. ## or {}) though the popup menu copes with this selection OK.

But even Geany's popup menu never works if your selection includes an odd number of double quotes (e.g. -“-).

The probable reason is that Geany never escapes any special character (e.g. # or ”) with backslash before passing selection to shell.

Another thing is that Geany only call the context action if something were selected. Empty selections are ignored. It's a pity because an empty selection may be as meaningfull as non-empty one. Cases as well as tastes differ.

You should take this into account, being aware of this behaviour of Geany.


Downloading

e_menu's zip file is available here:

tcl_geany.zip

or here:

aplsimple.ucoz.ru

Notice that e_menu is still disposed to update. At least I would try and support its aplsimple.ucoz.ru version in a working state.


Acknowlegements

Probably, e_menu and this wiki would be impossible without good advices of Enrico Tröger and scrupulous help of Matthew Brush. I am much obliged to both of them. And to all of Geany team as well, of course.

I'm still under the deep impression from coding in Geany and am still learning its hidden treasures and wonders.

To be so light and at that to be so predictable and powerful as those software behemoths like Eclipse or PyCharm - isn't it a wonder?

Also, the applied tool, namely the great and awful Tcl/Tk would never stop to amaze as well. Though the first impression of Tcl is 'What a s…!' Second, third, fourth and ..th impressions are the same till one day this thing begins to tease your brains and make to wonder.

An unexpected and pleasant discovery had occurred while me coding e_menu, namely the wonderful Fossil VCS. Somehow its power and lightweight resemble Geany's.

And these wonders tend to become a movable feast.

Thankful so much to all
Alex Plotnikov


See also

Print/export