This is a set of examples for those who just want to get their hands dirty without going into the finer details of jot - such details may be found in the jot user guide and the jot technical guide.
Examples Syntax
Back to JOT Examples
Forward to Basics
In the forgoing text the following shorthand applies (see About metasyntax):
$ <a CLI Command>
N.B. literal env-variable references of the form ${<envVariableName>} (e.g: ${JOT_HOME}) should not be confused with the {<key>} metasyntax.
The name of the key given in the curly brackets is generally the name printed on the key cap. The main exceptions are the beancounters keypad where the key names are prefixed KP_ and the cursor control keys referred to as {UpArrow}, {DownArrow}, etc..
Basics
Back to Examples Syntax
Forward to Starting jot for the first time
Jot is a command-driven screen-based editor - it obeys commands either typed-in directly or picked up from function keys etc and it maintains an screen image of the text being edited and displays changes as they happen.
Text is held in buffers, in the form of a complete file image or fragments. Jot maintains a number of buffers. Each buffer is identified by a single character key, typically A to Z, 0 to 9 and the various punctuation marks etc. In addition to these buffers may be created and destroyed in the jot operand stack - more about that later but, for anyone wanting to disappear down that rabbit hole right now - take a look at the stack.
Jot has a small number of primitive commands and some structure-building syntax elements. On completion, most commands return a success/failure indication which can be picked up by the structural elements of the language.
Sequences of commands can also be held, as text, in buffers (a macro) and macros can be run and will deliver status results like the primitive commands.
Starting jot for the first time
Back to Basics
Forward to Look at the jot display
The usual way to start jot is from a command line - i.e. an xterm (linux) or a console (windows). It is also possible to set it up to fire up from an icon of your choice - but then since you can't explicitly-specify a pathname you will have to hunt around in some idiotic menu to identify the file you already knew you wanted to work on.
Assuming your environment is set up correctly (see installation) in linux you can start the editor from the command line from an xterm like this:
$ jot ${JOT_RESOURCES}/Richard_III_Entire_Play.txt
In windows, start from a windows console (or MS-DOS prompt window) with exactly the same commend:
$ jot ${JOT_RESOURCES}/Richard_III_Entire_Play.txt
notice that the JOT_RESOURCES env is presented in the unix/linux form ${<envName>} - this form is ignored by the MSdos command-line interpreter which passes it through to jot. You are, however, at liberty to let the CLI do the translation thusly:
$ jot %JOT_RESOURCES%/Richard_III_Entire_Play.txt
You should see the text appear in your terminal window - as the name suggests it's Richard III by Shakespere. This text was chosen as it's long, well known and very much out of copyright. This version was downloaded from: http://shakespeare.mit.edu/richardiii/full.html - thanks.
At the bottom of the terminal window you should see the prompt "1 .> " This is an invitation to type commands to the editor the '1' is the line number, the '.' is the buffer key - see below.
Look at the jot display
Back to Starting jot for the first time
Forward to Jot Messages
Look again at the Richard III session you started earlier.
The startup script (more about that later) has set the size of the main viewing area to leave you with one line in the console area. Any messages sent by the editor are displayed by encroaching into the display area, they will disappear when you enter a command or just hit {Return} This allows you to see any messages jot sends to the console area. After you've looked at the messages hit return to clear them off the display without affecting the text in any way:
> {Return}Now look now at the top-left corner of the window - it should be displaying a tilde ( ~ ) in reverse video. The reverse video indicates that this is the current cursor position, the tilde indicates that the cursor has moved to the right of any displayable text - that's because this file starts off with an entirely blank line.
Jot Messages
Back to Look at the jot display
Forward to Some basic commands to get started
We will be seeing a lot of error and warning messages soon - so it's a good plan to know what they look like and understand what they're saying. We're going to type in a command that's guaranteed to generate a warning. Just type in the letter ( r ) and then return - r is the command to move the cursor one character rightwards and, since it's already at the end of a line, jot will inform you that the command failed:
> r {Return}The response should be:
{Command-sequence failed.}(1)rThe message comes wrapped up in curly braces followed by a number in brackets and the full command line, with the failing command highlighted. The number following the message is the command counter, this counts commands executed up to and including the failed command since the command was launched by the {return}. It is useful for debugging long complicated command strings involving macro and function calls.
Now try this:
> m1234m-1234r23m1234m-1234This first tells it to move the cursor 1234 lines down the file, 1234 lines back - it did that alright and, unsurprisingly, we ended up exactly where we started. It was then instructed to go right 23 characters then forwards and backwards 1234 lines again. It's the same message, but now the highlighting identifies the failing command ( r23 ).
Some basic commands to get started
Back to Jot Messages
Forward to Some Basic Function Keys
These are the most basic operations for anything claiming to be some sort of text editor - staying with the session you started earlier:
Look at the screen, in linux the ( k ) in kink is displayed in reverse video, the remaining characters are underlined the k is now the current character and the substring "king" is the current substring - we'll be looking at the significance of that later. In Windows, the current character and current substring are displayed differently.
To find the next instance:
> {F8} > {F8}the editor remembers the last-searched substring so you don't need to retype it. {F7} is similar except that it searches back up the text.
> {F7}it goes back up the text locating the previous instance of "king".
That's all there is to command-driven working, note the absence of any special manoeuvres to get it to take your command - you just type something in, hit return and your entry is taken as a command.
the currently-selected substring is changed to "aardvark" and this word becomes the currently-selected string.
In addition to those text-editing primitive commands, there are a number of housekeeping commands, dealing with I/O (input and output), interaction with the operating system, adjusting parameters of the display and parameters and querying system information. Lets start off with a few essentials:
or
> This is a completely new line of text I've added.{Esc e}Notice that the new line inherits the indentation level of the previous line.
Some Basic Function Keys
Back to Some basic commands to get started
Forward to Do a few easy edits with function keys
AgainExhaustive replies with: "Completed 450 repeats of ..." Note that the reported count does not include the original command. Note that AgainExhaustive will count successful repeats of any function or command string but some functions, by their nature will *never* fail.
To insert some new text into a preexisting line, move the cursor to the required place then use the Insert function.
> <newTextString>{F6}To insert a new line of text, there is the Enter function for entering new lines of text - either {KP_Enter} (that's the enter key on the numeric keypad) or, if you don't have a numeric keypad, then {Esc e}:
> <lineOfText>{KP_Enter}or
> <lineOfText>{Esc e}Continue to play around with the text file:
$ jot ${JOT_RESOURCES}/Richard_III_Entire_Play.txt
To see all of the available function keys and to explore their functions in jot, start up a qr (quick-reference) session:
$ jot -st=qr
or follow this link: jot quick reference
Do a few easy edits with function keys
Back to Some Basic Function Keys
Forward to A few more basic function keys
Try out a few of the edit keys mentioned in the Some Basic Function Keys section. For full details and all the other predefined keys look at functions defined at startup and key bindings. First try hitting the cursor-control keys a few times - one surprise may be that the up and down-arrow keys move to the start of the next/previous line. Why-so some may ask - after all every decent editor aims to hold the cursor to a column? Put simply, the jot behaviour is more likely to be useful and, when it is required to hold the cursor to a column, jot offers a more predictable way of defining which column - see NewWordUp and NewWordDown.
Now try the up/down/left/right-arrow keys while holding down the Shift key - this moves left or right by a full word or up and down in a column.
Try a search using <<FindNext>> the {F8} function key, note that, in jot, arguments to functions are entered before hitting the function key:
> gloucester{F8}Now just hit {F8} a few more times with no search string - each will find the next instances of "gloucester" {F7} key is similar but searches back:
> {F7}Now use the <<Insert>> function ({F6}) to insert the string abcdef
> abcdef{F6}Now, using the <<Substitute>> function ( {F5} ) to change that to 123456
> 123456{F5}Now play around with the <<FindNext>> {F8}, <<FindBack>> {F7}, <<Insert>> {F6} and <<Substitute>> {F5} keys. Then re-read a clean copy of the original file with the %I command:
> %i.{Return}This re-reads the original file into the buffer, destroying all your changes. If you're concerned that jot doesn't prevent you throwing away your precious work, take a quick look at about not losing your work.
A few more basic function keys
Back to Do a few easy edits with function keys
Forward to Deletion and restoration of text
Every editor has to have some way adjusting the view and of copying and moving slabs of text.
In jot cut and copy operations are done by first noting the start of the desired section and then moving to the end of the section to copy or cut (abstract in ecce-speak).
First move away from the start of the text image and then try the ViewUp and ViewDown functions:
> york{F8} > 10You located the next occurrence of "york" and then repeated that command a further 10 times - typing a number always gives you the specified number of repeats of the previous command.
> {Ctrl+Shift+UpArrow}This shifts the view up the screen by one line.
> 10{Ctrl+Shift+UpArrow}This shifts the view up the screen by ten lines.
Next try copying a section of text:
> {Ctrl+Shift+F1}This sets the note point at the start of "YORK"
> {F7}Locates the previous "YORK"
> {Ctrl+Shift+F3}This has copied the slab of text.
> zq{return} > {Ctrl+Shift+F4}We've moved to the buffer ( q ) and copied the text there. Now return to the main buffer.
> z.{return}Deletion and restoration of text
Back to A few more basic function keys
Forward to Getting help
In the context of the word-orientated functions, a word is any string of ascii alphanumeric characters bounded by either non-alpha characters or the start or end of the line. At present jot treats all unicode as non-alpha characters.
Note that there is only one graveyard for deleted text (the % buffer). All <<Delete...Right>> functions move deleted text to the end of this buffer, all <<Delete...Left>> functions move text to it's start. This means the <<RestoreWord...>> functions will restore characters and words deleted by the <<DeleteChr...>> functions and similarly <<RestoreLine...>> functions will restore words and characters that were not part of the original deleted word.
Getting help
Back to Deletion and restoration of text
Forward to Jot windows and views
Jot supports an online help system. The <<Help>> function uses specially structured files derived from ordinary jot documents (see About help files). The structure of these documents is quite simple, entries are bounded by fold marks '{{{' and '}}}' at the beginning of a line and these may be nested to any depth.
The help entries you are about to look at are images of files in ${JOT_RESOURCES}/help/...
> {F1}When the <<Help>> function is invoked for the first time in a session, it presents you with the contents of the file ${JOT_RESOURCES}/help/help.hlp yours should contain some instructions and three entries:
[jot]jot [demo]play - An (almost) empty help category for you to play with. [your_stuff]play - For you put your own stuff in.The square brackets indicate that this is a file fold - it is currently empty. Opening it causes the file to be read. The cursor should already be on the jot entry, open it by calling <<Help>> again:
> {F1}It opens up similar screen but this one contains four entries - these are all help files made from jot documentation. The cursor should be on the jot_ug entry so open that one:
> {F1}This page announces that you're looking at the jot user guide and contains just two entries - these correspond to the two top-level entries in the user guide.
To descend another level down the hierarchy move the cursor to any part of a line starting with a fold mark and hit {F1}, to return back up the hierarchy move the cursor to any line without a fold mark and hit {F1}.
At any time you can return to your original work buffer e.g:
> z.and then return to the help entry you last looked at:
> z;Jot windows and views
Back to Getting help
Forward to Line shuffling
Jot splits terminal into various sections referred to as windows, by default, jot displays only one buffer in a simple window as described previously in Starting jot for the first time.
It is possible to split the display to view more than one buffer at the same time. These functions are provided to help you tweak the display to let you see everything you need to look at:
First try a simple horizontal split. Start a session on Richard III:
$ jot ${JOT_RESOURCES}/Richard_III_Entire_Play.txt
Now read in another two buffers with different files:
> %ia=${JOT_RESOURCES}/UTF-8-demo.txt > %ib=${JOT_RESOURCES}/l99.tYou should end up looking at l99.t in buffer b. Now do a simple horizontal split:
> {Esc w h}The screen is now split between to (roughly) equal windows, the tom one is dedicated to buffer ( B ) (this buffer was current when WindowHorizSplit was called, and a floating screen, currently displaying nothing.
The floating window will display the current window except, as is the case, when the current window is already displayed in another window. Let's display something in there - go back to the primary buffer:
> z.Back comes Richard III, go back to the UTF-8 test file:
> zaInvoking WindowHorizSplit will add another window by splitting the screen into three roughly equal windows ... etc. But now try splitting vertically. WindowVertSplit will count how many windows are currently in the display and reconfigure the display as n+1 vertical slices, where n is the current window count.
> {Esc w v}The screen is now split into three vertical slices, the first (leftmost) slice is dedicated to buffer ( B ), the next (centre) is the uTF-8 demo and the last (rightmost) slice is floating because the current buffer is being displayed in the centre window. Switch to the primary buffer to fill that floating window.
> z.Now save this window configuration using WindowSave:
> {Esc w s}The display flips back to the default single-window display. WindowSave can be given an optional name parameter allowing you to save any number of named window configurations but for now, we'll keep it simple. Try shrinking the window by one line:
> {Esc w -}or
> {Ctrl+Alt+UpArrow}Repeat either of these a few times (remember {F10} will repeat the last command). This expands the console area allowing it to display more lines of messages.
Now stretch the window with WindowStretch
> {Esc w +}or
> {Ctrl+Alt+DownArrow}Repeat until you're back to a single-line console area.
In a split-window environment these functions stretch or shrink the window displaying the current buffer - split the window again:
> {Esc w h} > za > {Esc w -}This shrinks the window displaying the current buffer ( a ). Repeat that a few times then switch back to the primary butter ( . )
> {Esc w -} > {Esc w -} > z.Now stretch this window:
> {Esc w +} > {Esc w +}Now restore your vertically-split display with WindowRestore - this, like WindowSave takes optional name parameters but our saved window configuration was saved with the default name.
> {Esc w r}In a vertically-split screen, WindowStretch/Shrink change the width of the current slice - go back to leftmost slice as this makes it easier to see what's going on the shrink by a few columns:
> zb > {Esc w -} > {Esc w -} > {Esc w -}Now back to buffer ( a ) and stretch:
> {Esc w +} > {Esc w +} > {Esc w +}Sometimes it's useful to have the line numbers displayed - most other times the linenumber prompt is sufficient and we don't want to waste screen space on line numbers. To display line numbers use the WindowWithLineNumbers function:
> z. > {Esc w l}Now move around in the main buffer - the linenumbers will follow.
When you've seen enough - make it go away:
> {Esc w l}Note that this line numbers display will only work with a simple window.
You can save and restore a view with the WindowSave and WindowRestore functions these also take optional name parameters. Move to any point in any of the three buffers ( . a or b ) and save the view with the default name:
> {Esc v s}Now go to some other point in any of the buffers and save a view with the name fred:
> fred{Esc v s}now go to any other point in any of the buffers and save that view with the name jim:
> jim{Esc v s}You may now hop around between these views:
> {Esc v r} > jim{Esc v r} > fred{Esc v r}...
Line shuffling
Back to Jot windows and views
Forward to Using matching functions
Sometimes, perhaps we're splitting a paragraph into two, all we need to do is to push some words from the end of one line and prepend them to the next line. Or, maybe, lop words from the start of a line and append them to the previous line. These two requirements are met by the <<AppendRightNext>> {{Alt+F10} and <<AppendLeftPrev>> ( {Alt+F9} ) respectively.
Returning to Richard III we notice that Shakespere could have achieved a more optimal text density. Given the size of a typical "complete works" there'd be loads more trees standing now if only if only he'd bothered to cram a few more words on each line. Let's sort it out for him:
> z.m-0 > by{F9} > {Alt+F9}That seems to have done it, but, oh dear! it doesn't seem to scan quite right now, maybe there is something to be said for his iambic pentameters after all - better put it back the way it was. Fortunately <<AppendRightNext>> will do exactly that:
> {Alt+F10}Another pair of functions, useful when editing programming languages, are <<IndentFromNext>> {Ctrl+Shift+F10} and <<IndentFromPrev>> {Ctrl+Shift+F9} - these change the indentation level of the current line to match, respectively, the previous line or the next line - first prepare some lines of differing indentation levels:
> z.m+20e4 mi/ /m-First inherit the indentation from the next line:
> {Ctrl+Shift+F10}then from the previous line:
> {Ctrl+Shift+F9}restore the text:
> {DownArrow} > {Ctrl+Shift+F10}Using matching functions
Back to Line shuffling
Forward to Buffers
The startup script defines some useful parenthesis and other matching functions:
In the Richard III text play around with the ParagraphUp and ParagraphDown functions:
> z. > {F4} > {F4} > {F4} > {F3} > {F3} > ...Open the test_block.txt file in your resources area - this has some simple examples of nested blocks and indentation:
> %it=test_block.txt;First do an indentation match:
> level 3 start{F8} > {Ctrl+Shift+F8}Another <<MatchIndentDown>> takes you into the curly brace match set.
> {Ctrl+Shift+F8} > {Ctrl+Shift+F7}Buffers
Back to Using matching functions
Forward to Copying and Moving Text - 1
In a modern text editor, the text you see on your screen is an image of the file as it currently exists as a text buffer in the computers memory. As the edit session progresses this may not match what's currently spinning in the filing system.
Jot supports a number of separate buffers each identified by a single-character key - the following buffers are accessible but some are used by jot scripts:
To change focus to another buffer we use the Z command
You should be in buffer ( t ) at present, let's go back to the primary buffer ( . ):
> z.{Return}Copying and Moving Text - 1
Back to Buffers
Forward to Adjusting focus and view.
No text editor is complete without some facility for picking up slabs of text to be moved or copied. In ecce-speak this process is abstraction.
The first step is to indicate the start point for abstraction with the N (note) command then move the cursor and then abstract to the destination buffer with the A (abstract) command.
Normally there is a dedicated buffer defined by the system for copying and moving slabs of text. Typically known as the paste/pick/put/copy ... buffer, in jot you can use any buffer you fancy - given that some buffers may be used by hot-key functions defined by the startup script - see buffers. The predefined hotkey copy/paste functions use the '_' buffer.
The basic cut/copy and paste keys use the jot note and abstract commands:
We're going to pick up the phrase 'glorious summer by this sun of ' from Richards opening soliloquy and reinsert them.
> Now is{F8} > {Ctrl+Shift+F1} > York{F8} > {Ctrl+Shift+F2}The first and second lines of text, as far as York, disappears.
> {Ctrl+Shift+F4}The text reappears.
The last two operations could have been performed by the copy function:
> m-0 > Now is{F8} > {Ctrl+Shift+F1} > York{F8} > {Ctrl+Shift+F3}At this point, the text is still in the paste buffer and can be inserted anywhere you fancy in any of the editors buffers. You can also make the paste buffer ( _ ) the current buffer to check what's in there:
> z_Now return to the primary buffer ( . ):
> z.Adjusting focus and view.
Back to Copying and Moving Text - 1
Forward to Some fancy flavours of find - 1
Some of these operations are best done with a file with very long lines (i.e. wider than your terminal) load the test_table.txt file into buffer w.
> %iw=test_table.txt;Note that you did not need to type in the pathname to read this file, jot first tries to read the file from your PWD (present working directory), if it can't find it in there it tries prepending the path from the current buffer - in this case ${JOT_RESOURCES}, it should find ${JOT_RESOURCES}/test_table.txt
The file you've just loaded is a tab-separated tabular file designed to show up any jot bugs affecting the display of tabular text. Later we'll find out how to display this file properly. For now we'll display it as linear text, jot displays tabs (and all other control characters) as tildes ( ~ ).
Do a few <<Down>> {DownArrow} and <<WordRight>> {Shift+RightArrow} operations until the cursor approaches the right margin of your window. Now do another <<WordRight>> {Shift+RightArrow} watching the display carefully. The editor is scrolling the entire view rightwards to bring the currently-selected word into view. Also try <<WordLeft>> {Shift+LeftArrow}
You can adjust the view manually with the <<ViewLeft>> and <<ViewRight>> functions ({Ctrl+Shift+LeftArrow} and {Ctrl+Shift+RightArrow} respectively), if you shift the view to the extent that the cursor slips off the left or right margin of the screen the editor will re-display the current section of the line in the console area.
Similarly, you can manually scroll up and down with the <<ViewUp>> and <<ViewDown>> functions ({Ctrl+Shift+Up/DownArrow}). Note that none of these functions affect the current editor focus, only the display - play around with these functions.
The <<WordUp>> and <<WordDown>> functions ({Shift+UpArrow} and {Shift+DownArrow} respectively) move up and down in a column. Now <<WordUp>> and <<WordDown>> use the ( Y ) primitive command. This will hold to the same column, ignoring the starting column. This behaviour is useful for moving up and down performing repetitive operations in tabular or similarly formatted text. But we will want to change column from time to time, this is done with the <<NewWordDown>> and <<NewWordUP>> functions ({Ctrl+UpArrow} and {Ctrl+DownArrow} respectively) . These reset the ( Y ) column offset to the current cursor position.
Now, tell the editor to display the text in this buffer as a table - we will be covering this in more detail in the next section. Just type this in:
> %b=tabstops -1and play around with the {Shift+[Left|Right|Up|Down]Arrow} keys. Also insert some text to make one cell wider:
> abcdefghijklmnopqrstuvwxyz{F6}and erase some characters from a cell to make it shorter than the others:
> e6{Return}Occasionally you will want to shrink the view in your console in order to display more of the system messages flying past. Especially if you are using the jot debugger. The function to do this is WindowShrink ({Ctrl+Alt+UpArrow}) or to expand the view there's WindowStretch ({Ctrl+Alt+DownArrow} each of these adjusts the window size by one line.
> {Ctrl+Alt+UpArrow} > {Ctrl+Alt+UpArrow} > {Ctrl+Alt+UpArrow} > {Ctrl+Alt+DownArrow} > {Ctrl+Alt+DownArrow} > {Ctrl+Alt+DownArrow}Some fancy flavours of find - 1
Back to Adjusting focus and view.
Forward to Some fancy flavours of find - 2
The standard startup script defines several more functions for finding text we're going to give them an outing now.
Return to Richard_III_Entire_Play.txt, it's in the primary buffer ( . ):
> z.The <<FindExact>> function (normally {F9} ) will only match to a whole word or number - i.e. one bounded by the start or end of a line or any non-alphanumeric character, in natural-language text this would typically be whitespace or a punctuation mark. We will be searching for exact matches to the string 'our' - first go to the top of the buffer:
> m-0 > our{F9}sure enough it matches to 'our' in 'Now is the winter of our discontent'
> {F9}this time it matches to 'our' in 'clouds that lour'd upon our house' notice it did not match to the word lour'd in the same line. The function <<FindExactBack>> ( {Shift+F9} ) does the same sort of thing but searches backwards.
Some fancy flavours of find - 2
Back to Some fancy flavours of find - 1
Forward to Some fancy flavours of find - 3
Now read the repetitive test file l99.t into buffer r, it's pretty dull but useful for demonstrating repetitive edits. Note jot is set up to respect env variables but only if they are expressed in the form ${<envName>}
> %ir=${JOT_RESOURCES}/l99.tFirst set the default find string to 'abc' and the default substitute/insert string to 'Abc':
> abc{F8} > Abc{F5}The <<SubsThenFindNx>> function will now repeat the substitution and locate the next matching substring:
> {Shift+F8}Hit {Shift+F8} a few more times. To repeat a command <n> times enter the number of repeats to the command line - let's change the next 10 occurrences of abc:
> 10To repeat the last command until something fails type zero:
> 0you should now be at the last line of the file (line 101) with all 'abc' changed to 'Abc'
Some fancy flavours of find - 3
Back to Some fancy flavours of find - 2
Forward to Locating text in columns and blocks
One more function, quite useful when dealing with natural-language text, is <<FindSequence>> {Esc f q} - this identifies a string of words irrespective of punctuation, whitespace and line breaks.
> m-0 > him a horse{Esc f q}it highlights the first word of the given list of words. The function <<FindSequenceBack>> ( {Esc - f q} ) is similar, except that it searches backwards.
Locating text in columns and blocks
Back to Some fancy flavours of find - 3
Forward to Using the Context-Proximity functions
These functions are probably not of much interest - except for specialised users dealing with text in line drawings, patterns for digital testing and digital simulation stmulii and reports. See The vertical-search functions for a brief description of what these functions do.
Full disclosure: jot has no find-vertical primitives - these functions are built entirely using normal left-to-right primitives.
First off, we need a sample of text containing meaningful text written from top-to-bottom in columns - we can make a suitable sample from Richards opening soliloquy of Richard III:
$ jot ${JOT_RESOURCES}/Richard_III_Entire_Play.txt \
-in="f/Now/r-0n.(rm)0aq&zq %h=call rotateDiagonal; m-0((i/ /r)0m)0 m-0"
What we've just done is copy the opening paragraph to buffer Q and rotate it around the leading diagonal. (see rotateDiagonal for details). Then to make it a bit easier on the eye, blank separator columns have been added. The four blank lines at the top correspond to the indentation of the original.
The text contains three instances of the word "clarence" towards the end of the passage (the original text is still available in buffer ( . ) if you want to check back), lets go and find them with the function findVert:
> clarence{Esc f v}The search is case insensitive, by default, notice that the vertical string is highlighted as black text against a magenta background. Now find the next instance of "clarence":
> {F10}and the final instance:
> {F10}finally, this fails:
> {F10}Notice that the current character is placed just to the right of the first character of the matching column. This behaviour simplifies repeated searches in the same direction.
There's also a backwards-searching version findVertBack:
> {Esc - f v}These functions can also be used to search for incomplete specifications using simple wildcards, similar to the filing-system filename globbing.
For example if we want to locate the line about Clarence being mew'd up:
> m-0 > Clarence\ *mew{Esc f v}The functions FindCol and FindColBack are similar except that they only operate in the current column.
> m-0r > discontent{Esc f y}As you can see, FindCol leaves the cursor immediately below the first matching character as does FindColBack:
> y20 > {Esc - f y}Now this is a pretty contrived example to demonstrate searching for a block of text ... but here goes. The words "clouds", "bosom", "brows" and "arms" all happen to align nicely in the scrambled text so we're going to find them. First we have to construct a 2-dimensional search specification in buffer ( Z ):
> %gzclouds
bosom
brows
arms :
Now run the search:
> m-0 > z{Esc f e}Note that this search specification is not rectangular, three of the search words are longer than the first word. the magenta rectangle it places over the matching text is in fact the closest-fitting rectangle and the height is determined by the longest matching string.
Using the Context-Proximity functions
Back to Locating text in columns and blocks
Forward to Regular expression usage
The <<ProximityPara>> {Esc f p} function finds the next paragraph containing all of the substrings in the blank-separated list argument. We're going to find the famous "A Horse, a horse my kingdom ... " speech:
z.> horse king{Esc f p}
the first matching paragraph is not what we're looking for so try it again:
> {Esc f p}nooo! try again.
> {Esc f p} > {Esc f p}Note that adding a second "horse" to the word list or changing the order of the list makes no difference.
The <<ProximityParaBack>> function ( {Esc - f p} ) is similar except that it searches back towards the start of the buffer.
This sample document is not structured into chapters recognisable to jot, the following manoeuvre reformats the scene-numbering lines. Note that jot's working definition of a chapter is any number of lines of text, bounded by the buffer limits or by lines containing an alphanumeric character in column 0. All this does is to identify these lines then remove the leading whitespace:
> m-0((v/ /r)0v/scene /e-0m, m)0Regular expression usage
Back to Using the Context-Proximity functions
Forward to Fancy flavours of substitution and insertion - 1
Many battle-hardened unix users are quite good at regular expressions, some may even enjoy using them (see %X for details). Here we're just going to demonstrate the jot %F interface to the gnu regular-expression functions.
> m-0 > %fa= -rex horse.*kingnow search back from, the end of the buffer.
> m0 > %fa= -rex -back horse.*kingFancy flavours of substitution and insertion - 1
Back to Regular expression usage
Forward to A detailed look at a tab-separated table
An occasionally-useful function is <<Overwrite>> ({Shift+F6}) which, as it's name suggests, overwrites whatever happens to be there with the given string.
Return to the test_block.txt this has some simple block diagrams.
> ztthis has a couple of simple block diagrams. There are some special functions for dealing with these but, for now, the important point about these diagrams is that if you just insert text with the simple <<Insert>> ( {F5} ) function it will mess up the picture to the right of the insertion point. For this job we need the <<Overwrite>> function - it's on {Shift+F6}. The first box lacks a label on it's third input:
> m+18r13 > i3{Shift+F6}A detailed look at a tab-separated table
Back to Fancy flavours of substitution and insertion - 1
Forward to Tabular text - 1
Return to the test_table.txt file,
> zwas we've already discovered, this contains table entries (cells) separated by tab characters - a special control character that emulates a manual typewriters tab key.
Manual typewriters! - remember them? Anyone who's looked inside of one will know exactly what tabstops are - little metal pegs that select where the carriage ends up after the tab key is pressed. This ensures that addresses, headings and tabular entries all appear in the right position on the paper. In computers and text editors a similar behaviour is mechanized with logical and arithmetic operations based on the tab character.
In jot tabstops work in much the same was as in manual typewriters - tabstops are a list of positions where the next column in the table is to appear. e.g. for four 8-character columns we might write:
%b=tabstops 8 16 24 32;
But it's a real drag typing in all that stuff - this command has the same effect:
%b=tabstops 8;
this sets the first column width to 8 and subsequent columns inherit the same width.
Setting the column width to -1 is an instruction to jot to calculate an optimal set of tabstops for the section of table that's currently in view.
Now, for tabular text we might find it easier if the header line was fixed in the window. There is a command to do this the line of text we want to use in this example happens to be the first line try typing in this command string:
> m-0%b=header 'wThe "m-0" element tells it to go back to the first line of the buffer, in this case, this happens to be the header line. "%b=header " is the command to set the header and the "'w" element indicates that the text to use for the header is in the current line of buffer w. With this set up we can move right down so the first line scrolls off the top of the screen and still see the header.
Play around with the <<WordRight>> {Shift+RightArrow}, <<WordLeft>> {Shift+LeftArrow}, <<WordUp>> {Shift+UpArrow} and <<WordDown>> {Shift+DownArrow} functions.
Tabular text - 1
Back to A detailed look at a tab-separated table
Forward to Tabular text - 2
When we look at some real tabular data using, say, a spreadsheet viewer we sometimes see that a cell has been truncated because the text-width in the cell is greater than the width allocated for that column. In contrast, our simple concept of tabstops will allow the cell to overflow into the next column - not really very desirable for real tabular data. Thus we have two slightly different settings:
Staying with the test_table.txt session, first set the tabstops all to 12 characters:
> %b=tabstops 12;now go to a cell on the screen and make it much wider:
> m-0f/colBrow15/i/This_is_now_a_very_wide_cell/The effect has been for the cell to encroach right across three columns - undesirable for tabular data like this. Of course we could set the tabstops to -1, then the editor would expand that column:
> %b=tabstops -1;But, what a spreadsheet viewer would do would be to mark the over-wide cell and truncate it. The tabcells setting approximates to this behaviour:
> %b=tabcells 12;Tabular text - 2
Back to Tabular text - 1
Forward to Colour-tagged text
A line of tabular text consists of substrings (cells) separated by value-separator characters. By default, this separator character is Tab and tabs are represented on the screen, like any other control character, with a tilde '~'.
Read a more typical spreadsheet table into buffer e.g:
> %ie=consumertrends2012q3cvmnsa_tcm77-292466.tsvand tell the editor to display this as 6-character cells
> %b=tabcells 6this is equivalent to saying %b=tabcells 6 12 18 24 30 ... i.e. the default cell width is the width of the previous cell.
The main body of the spreadsheet should display in a nice neat tabular form with 6-character columns - not quite wide enough for some cells. In particular, the first column of the main spreadsheet is a year followed by Q{1-4} - this requires at least 8 columns to display clearly. When you've not given a column sufficient to display a cell, the cell is repeated in the console area of the screen. Looking a that we can see that the first column needs at least 7 characters to display properly.
We could ask the window manager to assign tabcells automatically, like this:
> %b=tabcells -1but some of the cells are very wide and tend to mess up the display.
Hit {Shift+DownArrow} and {Shift+UpArrow} a few more times, sufficient to scroll the screen - taking note of the way the column widths change. This is because tabcells -1 will adjust the column widths to accommodate the widest column-cell currently in view. See %b=leftoffset and about long lines.
Try this instead:
> %b=tabcells 8 16 22This makes the first two columns 8 characters and subsequent columns all inherit the 6-character width assigned to column 3. Also, the initial comments are in very wide cells and much of this text has been truncated. If the cursor ends up in a cell that, for any reason, has been truncated it repeats the cell text in the console area like this:
> m-0f/Hairdressing/In the console area you should see something like this, showing the cursor in truncated cell and bits of it's neighbouring cells. If, as might happen in this case, you still can't see all of the cell, then press {RightArrow} until all of the cell is visible in the console area - it should look something like this:
onal care~Hairdressing salons and personal grooming establishments~Electrical ap
Finally, when scrolling through a spreadsheet it's useful to have a static header at the top. For this file we might chose the 4-character column key, this is on line 13 of the file:
> m+13 %b=header 'eColour-tagged text
Back to Tabular text - 2
Forward to Graphical text - 1
Jot supports user-specified colouring for specific strings in the text. In jot this is referred to as tagging text. There are two stages to the process first we define a colour scheme and assign it a name (see %b=tagtype) and then the tags can be added to the text (see %b=addtag).
We're going to define two colour pairs - a foreground and background colour combination is known as a colour pair. the colours identified by numbers in the range 0 to 7 - see %b=TagType for details.
> %b=tagtype normal colour 7 0 > %b=tagtype red colour 7 1The colour pair normal is used to switch back to normal text colour after the coloured-in cell. Now let's stick some colour on a cell:
m+40r8 %b=addtag red; r5 %b=addtag normal;r-0
Well it would be a real drag having to go round spreadsheets adding tags manually. In practice, the useful thing about colour tags is that they can be used to highlight important details that might otherwise have been missed.
Suppose we were interested in places where an entry for one row is less than the previous entry Now pick up the following, down-to and including '$ line, then drop it into the console area. It defines a little macro that highlights in red any cell that has a lower value than the corresponding cell in the previous year.
%g$ %%Macro to highlight spreadsheet entries where on year's entry in a column is less than the previous year. %% %%Clear any preexisting colour tags. m-0n.m0a@h@ %%Locate first row with digits in column 1 - assumed to be the year. m-0(q/0-9/\m)0 %%Initialize column counter. ol0 ( %%Column loop - index to next column, initialize previous-cell value to 0 then find start of yearly entries.
ol-1o+ ol0os m-0f/1997/ ( %%Year (Row) loop.
mm- %%Step past the year column. ((q/0-9 Q/r)0rq/0-9/\m)0 %%Now index to the current column. o# (o~ (q/0-9/r)0 r)0 ok (rr-, okokr-0 %x=All done;) %%Pick up value from this cell and compare it to previous. os (oid oso> %b=addtag normal;, %b=addtag red;) mos )0 osok )0
: '$
Note that these tags can not persist beyond the current session, it's all done with metadata that is not part of the plaintext file.
Graphical text - 1
Back to Colour-tagged text
Forward to Graphical text - 2
With this type of text, it is important to preserve the position of text to the right of the cursor. It is also important to have some line-drawing and block-move operations.
The most convenient way of doing this is with a numeric keypad - the startup script attaches the functions to the various numeric-keypad keys. Windows users should find these work anyway but linux users will have to set up the keypad with xmodmap - see X-windows setup. If you don't have a numeric keypad and you want to have a go at this, the functions are available as escape sequences but, trust me, it's a real drag doing it that way.
First clear buffer r by abstracting an empty string to r (it should be empty anyway) then move into it:
> n.arzrThe buffer is completely empty, notice that the cursor-control keys ({[Left|Right|Up|Down]Arrow}) fail to shift the cursor off the top-left corner of the screen because there is no text to navigate.
In the empty buffer, you can navigate around using
> {Ctrl+KP_4} > {Ctrl+KP_2} > {Ctrl+KP_6} > {Ctrl+KP_4}These are attached, respectively, to the <<Left>>, <<RightRegardless>>, <<UpRegardless>> and <<DownRegardless>> functions the latter three insert blank lines and whitespace into the buffer as necessary.
So first have a little play with these keys. Move the cursor to somewhere near the centre of your screen.
Now draw the first hyphen of an easterly line by hitting
> {Ctrl+Shift+KP_6}These call the <<LineE>> function. Now hit the repeat key {F10} five times you should see a horizontal line of six hyphens with the cursor one place to the right of the last hyphen.
Now draw a vertical line down using the <<LineS>> function, this is on
> {Ctrl+KP_2}or
> {Esc l s}and repeat this five times by hitting {F10} 5 times. Notice the corner - <<LineS>> detects the change in direction and left a blank at the corner to avoid any untidyness.
> {Ctrl+KP_4} or {Esc l w}will draw a horizontal line using the <<LineW>> function - again it detects the change in direction and puts a blank at the corner. Finally
> {Ctrl+KP_8} or {Esc l n}will draw a line going up, using the <<LineN>> function.
Graphical text - 2
Back to Graphical text - 1
Forward to Graphical text - 3
In the previous section we looked at drawing wit simple ASCII characters namely Hyphen ( - ), vertical Bar ( | ) and blanks ( ) the latter, although not explicitly mentioned, are used to form corners and intersections.
In this section we'll look at how to use the unicode line-drawing characters. It turns out there are quite a lot of them. In addition to horizontals and verticals there are various corners and intersection characters - and three line-drawing font-styles - light lines, heavy lines and double lines.
As we've already seen, jot's line drawing defaults to simple ASCII hyphens and vertical bars, the first thing to do is to select one of the unicode line-drawing fonts. In the following we'll select light lines.
> l{Esc l d}Now move the cursor to a suitably-empty part of the screen (using {Ctrl+KP_8}, {Ctrl+KP_2}, ... And start drawing:
> {Ctrl+Alt+KP_6} > 5 > {Ctrl+Alt+KP_2} > 10 > {Ctrl+Alt+KP_4} > 5 > {Ctrl+Alt+KP_8} > 10 > {Ctrl+Alt+KP_6}Now move upwards and rightwards a couple of times:
> {Ctrl+KP_6} > {F10} > {Ctrl+KP_8} > {F10}Now draw a line down into the box
> {Ctrl+Alt+KP_2} > {F10}Notice that it has replaced the simple horizontal with an inverted-T intersection character. Now draw the line one step further down, into the box.
> {Ctrl+Alt+KP_2}Notice that the inverted-T has been replaced by a crossover character and it has drawn another vertical-line character.
Now let's change font to double lines.
> d{Esc l d}and start drawing towards the left side of the box.
> {Ctrl+Alt+KP_4} > 6It has inserted the correct crossover character.
Now for the bad news:
C D |
A ╶─────┬─────┼───────── B |
│ │ |
v ^ |
The line A to B was drawn initially, the line down from C was successfully added by starting at C and drawing down. The similar line was drawn upwards towards point D, instead of inserting a tee when it joined the vertical, it was necessary to draw past the horizontal and so ended up with a cross.
Graphical text - 3
Back to Graphical text - 2
Forward to Graphical text - 4
The <<LineNE>>, <<LineNW>>, <<LineSE>> and <<LineSW>> functions draw diagonal lines with Slash and Backslash ( / and \ ) characters. On the numeric keypad these are attached to {Ctrl+KP_9}, {Ctrl+KP_7}, {Ctrl+KP_3} and {Ctrl+KP_1} respectively (for those without a numeric keypad use the following instead: {Esc \ u}, {Esc / u}, {Esc \ d} and {Esc / d}).
Try drawing a few lozenge shapes with these keys and draw a few lines mixing these with the horizontal and vertical drawing functions.
To cut and paste blocks of this kind of text use the <<Note>> {Ctrl+Shift+F1}, <<CutRectangle>> {Ctrl+Shift+Alt+F3} and <<PasteRectangle>> {Ctrl+Shift+Alt+F4}. The note point must be at the top-left corner of the rectangle you want to cut. First position the cursor to the top-left corner of the rectangle to be cut, then hit note:
> {Ctrl+Shift+F1}then move the cursor to the bottom-right corner of the rectangle and cut the rectangle:
> {Ctrl+Shift+Alt+F3}The cursor should now be back at the original note point and all the text in the rectangle has been replaced by whitespace.
To restore the original text use the <<PasteRectangle>> function - {Ctrl+Shift+Alt+F4} before moving the cursor. Then move to the place where you want the top-right corner to go and apply <<PasteRectangle>> again.
To create a complete box use the <<Box>> function, it takes two arguments, the box width and box height with the top-left corner at the current cursor position:
> 7 5 {Esc b x}This creates a box 7 characters wide by 5 lines high.
To create a complete lozenge with it's apex below the current cursor position use the <<Lozenge>> function:
> 6{Esc z 1}The DSLozenge function is similar except that the horizontal pitch is doubled:
> 6{Esc z 2}Graphical text - 4
Back to Graphical text - 3
Forward to Insert mode
Each of the line-drawing functions take an optional text-string argument - this allows you to draw using text strings when required. For the functions that draw right-to-left or bottom-to-top, the string is reversed to make it easier to read (left-to-right or top-to-bottom).
Navigate to the centre of your screen and type:
> This can be read top-to-bottom{Esc l n}Now create a small box of 7 characters wide by about 5 lines. Now navigate to anywhere in the box and insert text using the <<BoxText>> function - {Esc b t}
> 7 4{Esc b x} > Text in the box{Esc bt}You should get something resembling this:
------ | Text | | in | | the | | box | | | ------
As an example of this type of text, open the text version of the jot user guide and go to the diagram showing the mid-keypad assignments:
> %iz=${JOT_HOME}/docs/jot_ug.txt > f/| 9 KP_9 |/r (ol1ow)12Set the note point at the top-left corner inside the box:
> {Ctrl+Shift+F1}then navigate to the bottom-right corner and <<CutRectangle>>:
> r17y6 > {Shift+Alt+F2}The text disappears - it's actually in the _ buffer - take a quick look:
> z_Now return and restore the text:
> zz > {Ctrl+Shift+Alt+F4}Insert mode
Back to Graphical text - 4
Forward to Command-editing
Up to now, everything has been types into the console area at the bottom of the screen. With, many modern editors the stuff you type in appears WYSIWYG-style (What You See Is What You Get) directly in the the text image image on the screen and, according to modern myth, WYSIWYG is always best. Indeed, if all you're doing is brain dumping your thoughts directly into a text-file image or sometimes when doing lots of fiddly but non-repetitive changes to a small block of text then this is a pretty good way to work - see Command-mode vs. insert mode.
Clear a buffer then zoom into it, put the editor into insert mode and just start typing.
> n.apzpThis switches the editor to insert mode:
> {Esc I n}Now just type in a few lines, each line is terminated by {Return} if you want to rub out something just press the {Backspace} key. This little nursery rhyme will do:
Tom, Tom, the pipers son stole a pig and away did run pig was eat and Tom was beat and Tom went howling down the street.
The cursor-control keys will all work just the same, as will most of the function keys. The exceptions are those which take parameters - e.g. <<FindBack>> and <<FindNext>> - these prompt you for a search string e.g:
> {F7}Find string> tom{Return}
now try {F7} again and hit {Return} in response to the "Find string>" prompt.
> {F7}Find string> {Return}
it finds the previous occurrence of Tom ok, but better yet, use <<FindBackAgain>> ( {Ctrl+F7 ) this repeats the search without prompting:
> {Ctrl+F7}{Esc I n} also exits insert mode.
> {Esc I n}You are now back in command-driven mode alternatively, {Ctrl+c} will also get you back to command mode.
In addition to the semi-perminant insert mode described above, jot offers a temporary version - {Esc i n} (see TempInsertMode) enters a insert mode that persists until the next use of any function, cursor or escape sequence.
> {Esc i n}Type in some text.
> {LeftArrow}More importantly, TempInsertMode can be used to temporarily exit the insert mode in order to type a command line to the console.
It works in pretty-much the same way for tabular text - in this example the tabcells mode and insert mode are set by the initialization sequence:
$ jot ${JOT_RESOURCES}/test_table.txt -in="%b=tabcells -1; %s=commandmode 2;"
Navigate your way around to any cell and type some stuff in. Note that, in order for you to see what you're doing, it initially displays your typing by allowing the enlarged cell to shift rightwards, encroaching into the neighbouring column. Then when you press any function or cursor key, the entire view is redrawn with the enlarged cell in a neatly tabulated and suitably widened column.
Command-editing
Back to Insert mode
Forward to Using the popup menu
There is a simple command-edit/repeat facility (see about command editing). It works my getting a buffer containing command-history and editing the desired command string in that buffer. By default, the command-history depth is just 20 lines, if you feel that is not enough, you can increase the size of the history buffer with the -history CLI qualifier. When you're happy with your command line you exit and your command line appears in the console area.
Typically command-editing offer a very restricted range of editing functions but are entered by simply pressing the relevant cursor keys. In contrast, jot's command editing facility requires one escape sequence to enter and exit it also switches focus to a different buffer, but, once you're there the full range of editor functions are available. It's also worth noting that the jot command editor allows you to operate over several lines of history. On exit you are returned to your original focus point.
Return to the Richard III text in the primary buffer and go to the start:
> z. > m-0Now fill the history buffer with simple commands - hold down the {DownArrow} key until you have passed line 20 (by default, the history buffer is 20 lines long - see -History). Then enter an easily identifiable command:
> %m=Hello world; r0pNow enter a few simple commands - the <<Right>> function will do:
> {RightArrow} > {RightArrow} > {RightArrow}Now enter the command editor:
> {Esc c e}Now insert "%d1=" at the start of the macro - so that the command text defines the macro attached to button 1. First navigate to the start of the "Hello world" line then:
> %d1={F6}Push the command back into the console command buffer:
> {Esc c g}You should be back in your original context and see the modified command string in the command area looking, for all the world, as though you'd just typed it in. At this point hit {Return} to run it.
> {Return}Take a look at the definition of macro 1 - we should see our original command:
> z1Using the popup menu
Back to Command-editing
Forward to Percent commands - 1
Jot has a simple yet useful popup menu. It can, for example, be used to reproduce hard-to-spell, hard-to-remember or tedious-to-type words in documents or object names in computer coding languages. The popup menu is also used to offer spelling corrections suggested by Aspell - see text document preparation.
For details see PopupSearch, PopupIncrementalSearch, PopupMouseSelect, PopupRestore, PopupScreenNext and PopupScreenPrev.
Fire up a session on RichardIII:
$ jot ${JOT_RESOURCES}/Richard_III_Entire_Play.txt
Search for words containing the sting 'men':
> men{Esc p s}You will notice a list of words appear, on a blue background, in the top-right corner of the screen - this is the popup menu.
Now select one of these words by moving the mouse cursor into the popup area and clicking the left button on the mouse - if you are unfortunate enough to be working with a laptop touchpad there is doubtless some equivalent motion.
Notice that the popup menu has disappeared and that your selected word has appeared in the console area. You can now apply this word in some other jot function - say Find:
> {F8}You might equally have invoked FindBack {F7}, FindExact {F9}, Insert {F6}, Substitute {F5}, etc.
When the search returns more results than can be accommodated in a 20-line popup, use the PopupScreenPrev and PopupScreenNext to view more of the list:
> {Esc p d}and
> {Esc p u}The function PopupIncrementalSearch is similar except that it searches the document as you type in the search string. This allows the search to be refined interactively. Note that the popup-menu clicks are disabled until the search exits by hitting {Return}.
We're going to go fishing for the word marquess, as this is a good example and appears in two different spellings. Again, with Richard III, start an interactive popup find:
> {Esc p i}Notice the prompt string, it's telling you that the search string is currently empty and that there are 0 matching words. Now type in the first character of our search string - I suggest ( q ) we shall see why later.
Currently 0 matching words> q
the popup appears with a list of words from the text each contains ( q ). Now type in the next letter - this has to be ( u ).
Currently 39 matching words> qu
Now try entering a ( e ):
Currently 39 matching words> que
Now add a ( s ) to the search string:
Currently 15 matching words> ques
Now remove the last letter with the {Backspace} key:
Currently 5 matching words> ques{Backspace}
We should be back to 15 matching words again. Now exit the search by hitting {Return}:
Currently 15 matching words> ques{Return}
Now, why did I suggest starting with the letter ( q )? This is not a very commonly used letter in english, if I were to have chosen a letter like ( a ), ( t ) or ( s) any of these would have matched to thousands of words in this text. Each match must be processed and this processing would have introduced a significant delay - try it:
> {Esc p i}Currently 0 matching words> s
After a noticeable delay it is ready to receive the next character - let's try ( t ):
Currently 1679 matching words> st
The delay is now much shorter because there are far fewer matches and much less processing. This could be a problem for big documents, the solution is to start PopupIncrementalSearch further down the search - it takes an optional parameter which is the initial search string.
First exit that search buy entering {Return}, then start the search with a short initial-search string:
Currently 309 matching words> st{Return}> str{Esc p i}
Currently 41 matching words> str
The searching and processing delay was hardly noticeable and we can now continue interactively.
Percent commands - 1
Back to Using the popup menu
Forward to The %Q group of commands - 1
These are mainly to do with housekeeping operations and system interfaces. %q (system Query) is an important one, it supports several queries. Essentially it offers you little peepholes to see what's going on inside the editor.
Another important one is %s (System settings) - changes various default settings inside the editor.
There's also %b (Buffer settings) - changes some default state in the current buffer. Only a few key options are explored by this introduction - see percent commands for more details.
Two quite handy ones are %M and %X, %m just sends a message to the console e.g.:
> %m=Hello world!; %m=You should also see this message.%X also sends a message but it forces an exit from whatever macro is currently running:
> %x=Abrupt exit.; %m=You should not see this message.The %Q group of commands - 1
Back to Percent commands - 1
Forward to The %Q group of commands - 2
First, let's look at the words on system queries - %Q, these report system and internal editor state. For most of these the destination buffer is mandatory, in these examples the report is directed to buffer z.
> %qz=versionThe editor focus changes to buffer z, this now contains two records, first the string 'version', followed by the editor version - this query is more useful than might be immediately apparent - it can be used by a macro to find out if it's running on windows or unix.
> %qz=dateBuffer z now contains two records, first the string 'date', followed by the date as reported by the system.
> %qz=env JOT_HOMEThis time it replies with the current value of that env variable.
> %qz=bufferThis replies with several lines reporting internal state for the current buffer - refer to query buffer for details.
> %q=SameSinceIOThis does not write a report, it simply sets the failure flag if the buffer has been changed since it was last read or last saved - i.e. the image in front of you is, possibly, different to the version held by the filing system.
The %Q group of commands - 2
Back to The %Q group of commands - 1
Forward to Percent commands, %B and %E
> %qz=dir ${JOT_RESOURCES}
This extracts a directory listing for your JOT_RESOURCES area. There are several options for extracting more information about the files - see query dir for details. Here's an example:
> %qz=dir -mtime -size ${JOT_RESOURCES}; > %b=tabcells -1If, by chance, you want the report ordered by file size, there are some options on the sort function that can help (see %b=tabsort):
Percent commands, %B and %E
Back to The %Q group of commands - 2
Forward to Comparing buffers with comp.jot
The %B commands set some of the buffer attributes reported by the %qz=buffer query above. You've already encountered two of these in the section about tabular data (%b=tabcells and %b=header) - another important one is %b=pathname - this sets the default pathName used by %O and some other commands that refer to the filing-system.
The %E command is very useful - it passes a command down to your CLI and, optionally, collects the reply in a nominated buffer.
> %ez=ls -l .The unix status for the command is picked up and defines the editor failure flag.
Note that many useful CLI commands contain semicolons (in unixland they do anyway), and escaping these with backslashes makes it difficult to predict what actually emerges after the various layers have stuck their oars in.
Jot also allows two-way communication between itself and interactive processes that are not fussy about receiving commands from a pipe (many text editors will refuse to cooperate unless they are speaking to a genuine tty device). Fortunately, gdb, for example, does allow this and so does jot. The significance of gdb is that we can use jot to wrap it up in an ide-like environment but for now we'll use jot.
In this example we will set up a child jot session with %E, using %P to control it and monitoring it's responses in the parent session. We will also define the exit command a "%A" - although that's only required in windowsland:
> %eq= -interactive jot ${JOT_RESOURCES}/l99.t -quiet -obey -tty -exit=%a;That should create a second jot session listening for commands sent from our session using the %P command it also defines the exit command - in this case %a. Linux users can check that this happened by going to another console and checking for the new process:
$ ps -ef | grep jot
You should see this one: "jot ${JOT_RESOURCES}/l99.t -quiet -obey -tty"
Windows users can check the process monitor.
Now send it a simple command and pick up the response in the attached buffer ( Q ):
> %PQ=p3the attached buffer should now contain the correct response lines:
p3{CR} __01: abc def ghi jkl mno pqr stu vwxyz:0123456789{CR} __02: abc def ghi jkl mno pqr stu vwxyz:0123456789{CR} __03: abc def ghi jkl mno pqr stu vwxyz:0123456789{CR}
The lines are terminated with Carriage-return characters because the slave session is set up to send this stuff to a terminal rather than a file.
You can send it any number of commands, the response from each is appended to the buffer. The session closes automatically when the destination buffer is re-initialized:
> z. n.aqComparing buffers with comp.jot
Back to Percent commands, %B and %E
Forward to Redefining function and hot-key mappings.
To detect differences between a pair of buffers use the comp.jot script. In it's simplest form, this compares the current buffer with some other nominated buffer - typically these might be a new and an old version of some text.
Fire up a jot session on an example file and place a slightly different version in some other buffer. Since the comp.jot script splits the screen, you might chose to increase the width of your terminal window before you start.
$ jot ${JOT_RESOURCES}/Richard_III_Entire_Play.txt \
-in="%iq; (f/thy/s/your/)0m-0f/horse/naaha3m-0 z."
The -initialization commands read in another copy of the sample text into buffer ( Q ) and changed every instance of "thy" to "your", it has also inserted two extra copies of the first line containing the string "horse" - let's now go and spot the differences.
> comp q{F2}The comp script has redefined the window configuration, we now have a vertical split with the left side showing the original text and the right side showing the modified text.
Looking down the display we see, sure enough, two similar lines highlighted with can forground and a white background, the same two lines are repeated in the console area where we see the expected difference.
We can search forwards for the next mismatching line, using macro 5:
> {Esc 5}Is is usual when searching forwards in jot, the mismatched lines are right at the bottom of the display. To see the mismatched lines in context, shift the current lines of all in-view buffers to the centre of their respective windows use the ViewAlignCent function to improve the view. (the ViewAlignTop {Esc v t} or the ViewUp {Ctrl+Shift+UpArrow} (for windows users {Esc v u} may work) functions might be useful, according to taste).
> {Esc v c}An alternative approach would be to set a window guardband (see %s=guardband) this prevents the current character approaching the top or bottom margins of the window by less than a specified number of lines - it defaults to 0 lines. Here we're setting it to 5 lines - it will make no difference now since you've already cantered the display but you will see the difference after the next operation.
> %s=guardband 5;Now find the next mismatching pair of lines:
> {Esc 5}This time, something different has happened - we can see that the two lines are completely different. This is because our initialization commands have inserted two extra copies of lines containing the string "horse". So again view it in context:
> {Esc v c}As a result of the duplicated lines, the two buffers are out of alignment. Repeated macro-5 calls will not realign the buffers - this requires some human intervention. One way would be to go into the modified buffer and move it's current line down by enough lines to make the next macro-5 call work. In the more usual case a section of text has been re-written and we need to re-align to some point soon after the texts reconverge. We would usually do something like this: z.f/With lies well/ zqf// But that's a bit of a performance so we could use another feature of macro-5. If it is given a parameter, then macro-5 assumes that this is a jot command sequence to be applied to both the buffers.
> f/With lies well/{Esc 5}In addition to macro-5 comp.jot also defines macro-4 - almost exactly the same except that it searches back towards the start of the buffer.
It also defined macro-6 this repeats a command string in the reference buffer. If you have performed some operation in the primary buffer (that's the one in the left window) then macro-6 will repeat that command sequence in the reference buffer (that's the one showing in the right window). To see macro-6 in action we first go looking for the well-known "a horse, a horse" passage using ProximityPara and using the context-proximity functions:
> horse kingdom{Esc f p}Finally, when you've seen enough of the split-screen display invoke WindowOne function to restore the normal display window.
Redefining function and hot-key mappings.
Back to Comparing buffers with comp.jot
Forward to Command-line options
The mapping of functions to keystrokes is performed by the standard startup script (see about startup scripts). Take a quick look at this file - in particular the definition of functions in the ( ' ) buffer.
> %iz=${JOT_HOME}/coms/startup.jotThis only defines the functions. The startup script calls a secondary startup script to curses_keys_<TERM>.jot to define the keycodes used to recognize keystrokes. In windowsland it's WindowsNT_keys.jot, take a look at one of the relevant files:
> %ix=${JOT_HOME}/coms/curses_keys_xterm.jotor
> %ix=${JOT_HOME}/coms/WindowsNT_keys.jotThe syntax is quite simple - each line has three entries first an 8-character keycode, a function name and finally an optional comment describing the keystroke but note that this is not a free-format file - the keycode must be passed out to 8 characters with whitespace.
The keycode 'xxxxxxxx' indicates that this OS does not support a key combination.
At the end of startup.jot we see this line
obz@m-0 (f1/<</\k, n.f1/>>/-a$&z:m-0f'$-n.r0a$&z@l0r8e0h$m, z@m)0 z^m-0h@ oz
this code merges function definitions from the ( ' ) buffer with keycode definitions from the @ buffer and adds them to the key-mapping buffer ^ this is the buffer where jot has to find key-to-function mappings.
Essentially, to redefine your own key mappings, you should create your own startup.jot which defines any new functions and a new key-map file to replace unix_keys/WindowsNT_keys.jot with a customized key-map.
Command-line options
Back to Redefining function and hot-key mappings.
Forward to Command Files
When we fire up a jot session we can simply type:
$ jot <pathName>
Jot has a number of CLI qualifiers (see command-Line qualifiers) but here we will only need to know about three of them: -journal, -init and -startup
$ jot ... -journal
may be abbreviated to
$ jot ... -j
This causes the editor to keep a journal which can be used to recover the session in the event of a crash or a power failure and
$ jot ... -init="<jotCommands>"
may be abbreviated to
$ jot ... -i="<jotCommands>"
After running the normal startup script, but before starting the normal interactive session, the given command sequence is executed.
$ jot ... -startup=<pathName>
may be abbreviated to
$ jot ... -st=<pathName>
Runs the specified startup script instead of default one.
By default, jot picks up the file ${JOT_HOME}/coms/startup.jot, this defines functions and key mappings described here and in the rest of the jot documentation.
$ jot ... -st
Runs the editor with no startup script. There will be no predefined functions and no predefined hot-key mapping.
Command Files
Back to Command-line options
Forward to Command-file library
Command-file library
Back to Command Files
Forward to The get script - 1
There are lots of command files (scripts) designed to take on specific functions. In some cases, the scripts may be a tad over-specfic but that's OK because it's easy enough to adapt them. here's a list of the most important ones:
The get script - 1
Back to Command-file library
Forward to The get script - 2
A most useful script, it is used to interactively browse the filing system directories and archive files - see get.jot for full details. It can pick up a path from any of the following sources in the priority order listed.
Most of these usages of get.jot result in the editor focus changing to a list of files in the ( + ) buffer. Subdirectory names are suffixed with a slash ( / ). To select a file, or to descend another directory, navigate down to an entry and do {Esc 0}.
it shows a list of all files in the root area.
This env is set to the default c include path by c.jot, for example.
> get stdlib.h{F2}The get script - 2
Back to The get script - 1
Forward to The get script - 3
Another useful feature of get.jot is that it will descend into archive files of various sorts. In unixland tar (Tape ARchive) is a popular archive format (including compressed tarballs). In windows zip is a common one and there's also the microsoft cabextract format. In linux get.jot recognizes these files by applying the file utility, in windows it goes by file extension. Various helper co-processors are used to do this, some of which may need to be downloaded from various providers (see get.jot for details).
There's a few little sample archives in ${JOT_RESOURCES}/test_get - lets see what's in them:
> get ${JOT_RESOURCES}/test_get{F2}Along with various test files and subdirectories there's test_get.tar and test_get.zip - let's try pulling something from test_get.tar:
> test_get.tar{F8} > {Esc 0}It shows you a list of files and directories in this small test archive. Ignore the directories (entries ending with {/}select the file test_get/hello.c:
> hello(F8} > {Esc 0}Note that the buffer has not been given a proper pathname - in window-terminator line it just says something like
"[ From CLI command ...
this is because the archive may contain absolute pathname, as this one does, and if it came from a different filing system you will not be able to write the buffer to this path. As it is, in all cases you must set the pathname (see %b=pathname) of the buffer before saving the file.
It's a similar story with spreadsheet file containing multiple sheets - let's take a look at the original xls file in ${JOT_RESOURCES}
> z+ > ..//{F7} > {Esc 0} > xls{F8}It first asks you for a buffer key - we'll put the sheet in buffer z:
> z{Return}It presents you with a list of sheets in the spreadsheet file - 12KN is the one we've looked at before:
> 12KN{F8}The get script - 3
Back to The get script - 2
Forward to doc - document preparation toolbox - 1
The get script recognizes some binary file formats and can launch co-processors to extract plaintext from them - see installation.
In the ${JOT_RESOURCES} area are some versions of the test file t.t in various formats:
get.jot uses tika (a java application supported by apache) to suck meaningful text out of these files.
> get ${JOT_RESOURCES}{F2} > t.pdf{F8} > {Esc 0}In response to the 'Buffer key?' prompt, tell it to read it into buffer x:
> x{Return}doc - document preparation toolbox - 1
Back to The get script - 3
Forward to doc - document preparation toolbox - 2
The doc script is a useful toolbox of basic functions for writers. We're going to try some out on some text written using the document preparation functions - see text document preparation. First read the plaintext jot user guide:
> z. > %iy=jot_ug.txtthis is another copy of the jot user guide, which was written using the document preparation functions.
One of the most important document-processing hotkeys is probably {Esc p a}, this re-formats the current paragraph. Let's add some text and then use this to reformat a paragraph:
> m+54f/-{Return} > blah blah blah blah {F6}we've inserted a few words to the text, but the paragraph is now out of alignment. re-make the paragraph:
> {Esc p a}Now let's try breaking and joining paragraphs. Suppose we decided we wanted the last sentence of this line to be at the start of the next paragraph. The function we're going to use <<AppendRightNext>> {Alt+F10}, remember, moves text to the next line past indentation.
> plain{F7} > {Alt+F10} > {Ctrl+LeftArrow} > {Alt+F10} > {Esc p a}The process can be reversed by using <<AppendLeftPrev>> {Alt+F9} -
> a text{F7} > {F9} > {Ctrl+RightArrow} > {Alt+F9}This time merge the lines by erasing the line break - the function <<DeleteChrLeft>> {Alt+LeftArrow} deletes the line break when at the start of a line, as it is now:
> {Alt+LeftArrow} > {Esc p a}doc - document preparation toolbox - 2
Back to doc - document preparation toolbox - 1
Forward to doc - document preparation toolbox - 3
Go to any line of text and enter a new line:
> This a new heading.{Esc h e}Notice that the new heading has the correct header numbers relative to the previous heading - but the next heading is now wrong. This will be fixed later.
Add three more headings at various header levels:
> This is at a higher level.{Esc a} > {Esc h +} > This is at an even higher level.{Esc a} > {Esc h +} > This is going back one level.{Esc a} > {Esc h -}Having added a new section may wonder what about all those out-of-sequence section heading numbers further along? ... Well {Esc H} is here to help:
> {Esc h a}All the section numbers have been fixed.
doc - document preparation toolbox - 3
Back to doc - document preparation toolbox - 2
Forward to dic (dictionary) and thes (thesaurus)
Spelling checks are an important part of document preparation - except for those of us who can remember all spellings and never miss-type a word. The doc.jot spelling check uses the gnu aspell programme - see Unix and linux setup,
First find a good-sized paragraph and drop a in few incorrect spellings.
> inner{F8} > bananaz {F6}} > {Esc s p}The word "bananaz" appears in the console area. {Esc s p} is useful as a quick check of a freshly-updated paragraph or use {Esc s d} to check the whole document.
Now check the entire document with {Esc s d}:
> {Esc s d}With the full-document spelling check the list of miss-spelled words is not displayed in the console but is held in a buffer (the @ buffer). The <<NextMisspelledInstance>> function finds the next instance of the current reported word and each new application of {Esc n i} will find the next instance of the current reported word.
> {Esc n i}Sometimes, the word is a correctly-spelled technical term or someone's name that appears dozens of times and we just want to skip to the next reported word - the <<NextMisspelling>> function does just that:
> {Esc n w}It can, sometimes, be a long process looking up words in a dictionary. A regular expression search of the lexicon can sometimes help. Use the <<GrepLexicon>> function to find the correct spelling of a word. Results are displayed in the console area, if there are too many to see whet you're looking for, you can browse them in the $ buffer.
> ^ac.*mpl{Esc l x}dic (dictionary) and thes (thesaurus)
Back to doc - document preparation toolbox - 3
Forward to c, jot, perl, sh, csh, skill, verilog, vhdl, tcl, edif, mif - code browsers.
These are quite useful for authors. They are indeed useful when reading text in difficult or archaic english. The dic.jot script is set to find the Gutenberg websters ebook - see installation. The scripts are designed around the Gutenberg Ebook version of websters dictionary and Roget's. These can be downloaded from the Gutenberg project - see dic.jot and thes.jot. The dic and thes scripts expect to find these in your JOT_RESOURCES area.
> dic{F2}The dic.jot script reads the dictionary and creates an index. Now the dictionary is pretty big - about 19MB and it takes a few moments to read. Once this is done it writes the index and, keep the faith, next time you run the dictionary script it'll go like the wind.
Once it's read it's book we can fire off a few queries.
> zythum{Esc 7}if you've not got a numeric keypad or it's not been set up, then this will do it:
> zythum{Esc 7}The thes script is based on the Gutenberg Roget's ebook. This script takes a list of words and returns the categories containing all of them. Queries are handled by macro 8. Note that, although the thesaurus contains phrases, the search does not currently support phrases.
On completion the $ buffer contains a list of headings for matching sections, the @ buffer contains copies of the complete sections.
> thes{F2} > party{KP_8}Now try intersecting it with another word.
> party clan{KP_8}c, jot, perl, sh, csh, skill, verilog, vhdl, tcl, edif, mif - code browsers.
Back to dic (dictionary) and thes (thesaurus)
Forward to Journal files and recovery from crashes
These all match block starts and ends in their respective machine languages. The functions are similar - {KP_2} (or {Esc 2}) searches forwards in the text for the next valid block-start token and then locates the corresponding block-end token. {KP_1} (or {Esc 1}) is similar but works backwards.
The browsers for c and jot have been used with recent versions of jot and are pretty bulletproof. Those further down the list have not been used much recently and may benefit from updating. We're now going to look at c and jot. First open a new editor session on some c:
$ jot $JOT_HOME/source/ed.c
To avoid corrupting the definitive file change the pathname:
> %b=pathname ./play.cNow load the c-code browser:
> c{F2}When you first hit {KP_2} there is a momentary pause while it maps all the blocks in the file. When it comes back, the focus has changed to a block end token ('}' in c) at the end of a c function definition. Further pumping of {KP_2} takes us to the end of successive function definitions. The {KP_1} key takes us back, but this time it goes to block-start tokens.
If the C-code contains mismatched curly braces, c.jot will fail creating the hashtable. In these cases use the plodding versions - {x KP1} (or {x Esc 1}) and {x KP_2} (or {x Esc 2}) these work by plodding through the code counting curly-braces. The backwards-matching macro (Macro 1) is less reliable in this mode of operation because C cannot be reliably parsed in reverse - nevertheless, it gets it right most of the time.
To descend into a block just move the cursor anywhere inside the outer braces and hit {KP_2} again - Run_Sequence is a function with plenty of internal structure:
> f/Run_Sequence()/f/{ > {RightArrow} > {KP_2}The c script uses hashtables, not for speed - although this is a most welcome by-product, but to improve the reliability of reverse scanning. The main pitfall of using hashtables is when there's a mismatch somewhere and we want to locate it.
The {Mod} key (normally x ) modifies the function of {KP_1} and {KP_2} so that, instead of using hashtables, they plod through the code. These functions can be useful in the quest for mismatched braces.
Journal files and recovery from crashes
Back to c, jot, perl, sh, csh, skill, verilog, vhdl, tcl, edif, mif - code browsers.
Forward to Some more advanced topics.
First start a jot session with the optional qualifier -journal - this causes jot to keep a journal of your activity. Since the JOT_RESOURCES files are normally read only, first make a working copy of Richard, then launch a jot session with journal files.
$ cp ${JOT_RESOURCES}/Richard_III_Entire_Play.txt . $ jot Richard_III_Entire_Play.txt -jou
Just play around using the keys and commands you've looked at in previous sections of this example - move around in the text, inserting, searching, substituting, copying and pasting. Also read in some other files and cut and paste from those into the primary text.
While you're doing all this, your activity is being recorded in a particular journal file - history.txt. Now close the session with %A and take a look at what's gone into the history.txt file:
$ jot Richard_III_Entire_Play.txt.jnl/history.txt
It begins by noting a few details of your session and files read the startup script. Then , a few lines down, there is a line like this:
<<Startup Sequence ends, buffer .>>As the words suggest, this point marks the end of startup-script activity. After this, most of the entries are of the form ~Xxxxx - if you're viewing it with jot, the escapes will be represented as tildes ( ~ ) - these are keycodes. For keys that take an argument, the argument appears as a prefix before the escape.
All the journal files and the journal directory are destroyed when the editor exits normally (the %C or %A commands).
The journal directory holds the following items:
Now restart the editor but with the recovery script as it's startup:
$ jot ${JOT_RESOURCES}/Richard_III_Entire_Play.txt -st=recover
you may recognize some of the activity flashing past on the screen.
What's happening is that the recover.jot script has read the raw records of your original activity from the history.txt file and has created a new script ( ./recover_now.jot, in your PWD), it's now following your original activity. Whenever it needs to read a file, it reads the archived version from the journal - see also about journal files.
While in recovery mode, jot %i, %e reads and some %Q queries are intercepted and return the same results as they did in the original session. Theses results are from files held in the journal directory. Also jot writes are disabled to avoid corrupting anything.
When it's finished, all buffers in the recovered session should be exactly the same as in your original session and reading and writing are back to normal. You may continue with the session as if nothing had happened, new commands will be appended to the history.txt file and file reads and writes behave as normal.
A quick way of comparing the recovered version of the file and version in the original session is to use comp.jot go back to the original session and write the current buffer, then in the recovery session type this:
> comp{F2}The comparison script splits the screen to display both versions side by side. On completion both windows should be displaying an identical view of of the file image.
As the original session fires up, it creates a new journal directory. A LOCK file is added to the journal directory, the LOCK is deleted when the session exits normally. In the event of an abnormal exit, the LOCK file remains in the journal. If a new jot ... -journal session is started, it first checks the old journal for a LOCK - if it exists then the session terminates abruptly without changing any files. The LOCK, or the entire journal directory can be deleted manually if desired.
Some more advanced topics.
Back to Journal files and recovery from crashes
Forward to A profiling macro
The following sections are of more interest to those seeking to write their own macro-commands, scripts and redefinitions of the startup files.
This section shows a few macro commands of moderate complexity , takes them to pieces and analyzes them.
A profiling macro
Back to Some more advanced topics.
Forward to How does this work - 2
Suppose we were interested in the distribution of words in this text - we might want to count how frequently each word appears in there - something like this will generate such a report in the @ buffer.
Begin by copying the text into the @ buffer and changing all alpha characters to lower case.
> m-0n.m0r0a@&z@ m-0(q/A-Z/c, r, m)0Place each word on a separate line then sort them alphabetically.
> m-0(q/a-z/(q//r)0b, rr-(q/a-z/\e)0, j)0 > %b=sortFinalize the report by counting instances of each word
> m-0 (r\j)0 r-0 (n.r0a$&ol1m(v'$r0v-'$o~k)0 m-oo/%5d - /m)0How does this work - 2
Back to A profiling macro
Forward to Macros
There were four lines of code involved:
m-0n.m0r0a@&z@ m-0(q/A-Z/c, r, m)0 m-0(q/a-z/(q//r)0b, rr-(q/a-z/\e)0, j)0 %b=sort m-0 (r\j)0 r-0 (n.r0a$&ol1m(v'$r0v-'$o~k)0 m-oo/%5d - /m)0
In the first line:
The second line chops up sentences to yield a list of all the words in the original file in their original order. Again, the q command detects non-alpha characters then the ( b ) command breaks up the lines on the word boundaries removing any more adjacent non-alpha characters with the ( e ) command.
In the third line, the %b=sort calls the system quicksort service (see %b=sort).
In the final line there are a few new commands:
Macros
Back to How does this work - 2
Forward to The stack - 1
We could scoop up all of those commands into a buffer. That would then become a macro command to generate a similar report for any text. Macros 0 to 9 are attached to numeric-keypad buttons 0 to 9 - so, for this example we're putting the commands into buffer 3 and adding some commentary.
The %g command is a good way of doing this - it copies all text from the keyboard into the specified buffer, until terminated with a colon ( : ).
> %g3%%Copy text to @ and change all alphas to lower case. m-0n.m0r0a@&z@ m-0(q/A-Z/c, r, m)0
%%Place each word on a separate line then sort them alphabetically. m-0(q/a-z/(q//r)0b, rl(q/a-z/\e)0, j)0 %b=sort
%%Finally, count up instances of each word m-0 (r\j)0 l0(n.r0a$&ol1m(v'$r0v-'$o~k)0 m-oo/%5d - /m)0 :
Now go to the original text and run the macro - KP_3 denotes button 3 in the numeric-keypad - if your keyboard lacks a numeric keypad then use {Esc 3} - the escape key followed by 3
> z. > {KP_3}The stack - 1
Back to Macros
Forward to The stack - 2
The simplest usage of the stack is just a temporary parking place for various fragments of numerical and textual data. It can also be used to perform simple arithmetic and logical operations including counting.
One common problem in the design of macro commands is that we need to switch context to some buffer to pick up some information and then return to the original focus - the stack is there to help.
> ob %q~=date; m os oz i'~ okThe stack - 2
Back to The stack - 1
Forward to Blocks - 1
Sometimes we need to go off somewere else in the same buffer and find our way back:
> oconf/fred/r4n.f1/ /a$ono-omorNotice it did a little bit of arithmetic there, on puts the current line number on the top of the stack, it subtracted one from the other and calculated the displacement to give om which takes it back to the original line.
It can also pick up numerical values from the text. This involves a text-to-numeric conversion - oid performs a decimal conversion, oix hex oio octal and oif floating-point. Here, we're going to pick up a value from the spreadsheet and insert it into some text using the formatted output oo:
> zem-0f/2011/r5 > oid z. oo/ In 2011, it was %d /Blocks - 1
Back to The stack - 2
Forward to Blocks - 2
Many editors have some special search-and-replace mode for repetitive changes to the text. Jot has no such magic mode - because it's got something much better: a block structure. It's the block structure that gives this editor it's real power.
Here you will find it useful to know about the following commands and syntactic objects:
Blocks - 2
Back to Blocks - 1
Forward to Working with large files
Here's a few examples:
> (f/fred/ l0 f1/jim/\)0Working with large files
Back to Blocks - 2
Forward to Working with large netlists
Jot has useful support for large and very large files - see About large files. we might chose to use the following definitions:
The approach adopted for large files involves the use of hash tables for fast navigation around the file, minimizing reliance on global searches. The approach for very large files assumes that most of the time we are only browsing these files in search of an answer to questions such as "why this timing violation" or "why that error".
First you might to just play around with a small file with a simple structure so you can see how it works before generating a sample large file, which again has a fairly simple structure. Perform a few operations on it and write it back to the filing system. The remainder of this section is about creating and working with a simple big-file generated by concatenating lots of hexadecimal file dumps. But if you happen to have a suitable CDL or physical verilog, you might prefer to skip this section and, instead, look at working with large netlists.
Here's the example with a small file with an easy structure. First make a local copy of l99.t as you may not have write access to the resources directory:
$ cp ${JOT_RESOURCES}/l99.t . $ jot -in="%r=big_file -file=./l99.t -grep=__.0: -trim=(f1/:/-e2r2e0m)0;"
The grep commands cause it to create index points at the lines __00:, __10:, __20,: ... The trim commands trim each line found by grep to a two digit key
This loads the section starting with the line "__30: ..." down to the line "__39: ... You can now launch more queries - if you query a section that's already loaded it will simply take you to the start of that section. Notice it does not attempt to preserve the original ordering - this unlikely to be important. When you write the file back it automatically corrects the section ordering.
Begin by making a sample file, not too large, one or two Gb is good - you will later use diff to check a modified version of the file - and that will take time. The following command will generate hex dumps linux binaries in /usr, the command can be adapted for windows systems. In the jot -init command string, the initial "ol1000000000" sets the requested upper limit on the destination file size -try it with a bigger file later.
$ rm big_file.txt
The following jot session will exit at when the big_file.txt gets to more than 1Gb.
$ jot -in="%eq=ls -RF /usr/bin/ /usr/lib /usr/lib64;? %r=ls2list; \
ol1000000000 m-0((%i.= -binary 'q; b2i'qb %o= -append big_file.txt;, ) \ %q$=file big_file.txt; f/ size = /-oid o> zqm)0 %a"
You can adjust the file-size limit by adjusting the ol1000000000 element of the line - you may also need to add a few more binary trees to the "/usr/bin /usr/lib /usr/lib64" list to get a more realistically big file.
The index file is built by giving big_file.jot a -grep and a -trim strings:
$ jot -in="%r=big_file -file=big_file.txt -grep=/usr -trim=(f1/:/-n.r0f-./.-a$m,m)0; %qz=keys;"
The big_file script takes you definition of the -grep string as a signal to create the index using grep. After that, it takes the optional -trim string to be jot commands which will do any post processing work required to tidy up the index entries.
Windows users can probably do something similar (assuming ls and grep on the windows search path):
$ rm big_file.txt $ grep -b "c:" big_file.txt | jot -quiet -in="(f1/:/-n.r0f-1./.-aam)0 %o=big_file.txt_index; %a;" $ jot -in="%eq=ls -RF C:\wbin C:\Windows C:\win; %r=ls2list; \
ol1000000000 m-0((%i.= -binary 'q; i'qbr0b %o= -append big_file.txt;, ) \ %q$=file big_file.txt; f/ size = /-oid o> zqm)0 %a"
$ jot -in="%r=big_file -file=big_file.txt -grep=/usr -trim=(f1/:/-n.r0f-.\\.-a$m,m)0; %qz=keys;"
After it's been generated the index remains valid until the main file is rebuilt or modified.
We launch the editor specifying the big_file.jot script in a big_file.jot-calling initialization sequence but no initial file. The initial and subsequent sessions can be started like this:
$ jot -in="%r=big_file -file=big_file.txt; %qz=keys;"
The file it reads is the index file we've just created, instead of displaying the index file, it is used to populate a hash table with entries for each named section in the big file. If you want a different name for the index file you could say this:
$ jot -in="%r=big_file -file=big_file.txt -index=<myPathName>;"
Before we read any of the real file let's check to see what's in the hash table, the command-line suggested above lists all keys in the ( z ) buffer. To do this interactively:
> z. %qz=keys;Notice each entry has a key, a seek offset and a bytecount, at the end of this report you will notice a few data objects defined by the big_file script, "pathName", for example is the main-file pathname.
Now pick up any name you fancy from the list of keys in buffer Z and pull in it's hex dump - I'm picking "grep" for no particular reason:
> grep{Esc b q}The screen should now be filled with a hex dump of the grep-command binary. Note that big_file.jot has added a separator line of the form:
------------------------------------------ <keyString>These are important because they are target points for hash-table entries that find sections later - if, at some later point, query "grep" again, instead of re-reading the dump for grep it will direct you to this section once more. These target points are also used if ever you want to write a modified file back to the filing system.
Now, if this were a useful big file, such as a CDL netlist or, maybe, some EDIF parasitic file, we might be more interested in referencing sections by features inside the sections like net names, model names ... whatever. In our case we look for features in the binary dumps - like this:
> E8 AE{Esc 8}This greps for sections containing that sequence of bytes and pulls them all in.
Finally let's make a few changes and write our modified version back to the filing system, add a few strings that are easily detectable with grep or diff:
> f/00 00/s/ZZ ZZ/Now write the file, note that original order in which you read the sections is unimportant and that all sections in memory will be written irrespective of whether you've actually changed them. The function bf_writeModifiedFile will copy sections from the original file to the new file replacing any that have been read with the relevant section from memory.
> {Esc b w}The file is copied to a new version of big_file.txt, the original is still available for comparison - it's been renamed to big_file.txt_orig. Now close the session and return to the CLI - check the differences between the two files:
$ diff big_file.txt big_file.txt_orig
Note: In general, once you have written a new version of the file you should re-index the file because the edits may have altered the length of your modified sections and hence will change the seek offsets for later sections.
Working with large netlists
Back to Working with large files
Forward to Working with collections of source files
The big_file.jot script has predefined the grep and trim procedures for indexing the subcircuits in either CDL or verilog netlists - note that the scripts can not do anything useful with behavioural verilog.
The following command lines show how we might fire up a session, creating a new index file, for both CDL and verilog:
> jot -in="%r=big_file -file=<CDLpathName> -cdlindex;"or
> jot -in="%r=big_file -file=<verilogPathName> -vlogindex;"If your netlist is very large, you might want to create the index in batch - this is a suitable line to go into a batch file:
> jot -in="%r=big_file -file=<CDLpathName> -cdlindex; %a;"This line does the same thing but exits when the index has been created.
The editor will start with a blank screen, subcircuits are added individually, on request using macro-7 e.g:
> <subcircuitName>{Esc 7}The subcircuit is appended to the primary buffer and a JumpObj (see about hashtables) is added to facilitate speedy navigation. Subsequent requests for this subcircuit will not re-read it but just focus to the same text.
Alternatively, one might request all subcircuits, whose definitions include a specific substring (the substring might be a net or model name, for example) - this one pulls all subcircuits connected to a supply line "vdd_2v5"
> vdd_2v5{Esc 8}If the index file already exists, then the -cdlindex or -vlogindex should be omitted. To generate the index as part of a batch script, add a similar line but including the command to exit the editor on completion:
jot -in="%r=big_file -file=<CDLpathName> -cdlindex; %a;"
At the start of every operation, the big_file.jot functions will check that the index file is up to date by comparing the big-file's datestamp to that recorded at the time when the index was built. If is finds a discrepancy it will refuse to cooperate.
When the big_file does not exceed the editors capacity yet is large enough to navigation by normal searches tedious, one might chose to read all the subcircuits at the start of the session by including the " -all" qualifier on the command line. In this case the index file is read and JumpObjs (see about hashtables) are added to facilitate speedy navigation.
> jot -in="%r=big_file -file=<CDLpathName> -all;"It is assumed that any file big enough to require the big_file treatment is not a primary source file but some intermediate generated by a CAD or similar system. Even so, there will always be a requirement to modify even these files and big_file.jot provides macro-9 for this purpose. Macro-9 operates in this way:
Begin by reading a few subcircuits into the editor:
> <anySubcircuit>{Esc 7} > <anotherSubcircuit>{Esc 7}...
Now pick any of the subcircuits and make some change - a change to the .SUBCKT line is easiest to check later. Now write the modified version of the big file:
> {Esc 9}If your netlist is big enough, you will notice a little progress indicator popup near the top-right corner of the display, when you are dealing with seriously large files goes from 0% to 100% quite slowly.
Before it started writing your file, it moved the original bug_file to <pathName>_orig, when it's finished writing diff should detect the change you have made.
Working with collections of source files
Back to Working with large netlists
Forward to First with multi_file.jot index files
The notion of index files has been broadened to encompass large collections of files which, together, define a complicated system. The first requirement, when faced with such a system, is to gain an understanding of how the various modules interact with each other. The script multi_file.jot has been designed to address this problem and a similar script ctags.jot which uses ctags files generated by the Exuberant Ctags programme.
The multi_file.jot script, like big_file.jot is driven by an index file but these index files refer to any number of source files. Remember that, for large files, the file was opened and the filehandle was associated with the buffer using hash-table objects that only need indicate a seek offset and section length in bytes. Now, for collections of files we need a different hashtable object that also holds the file pathname. These objects are set up using the %H=setfsect command.
First with multi_file.jot index files
Back to Working with collections of source files
Forward to Now a Ctags-generated index
The following should work for any GNU download - in this case I chose an ncurses 4.2 download:
$ ls -laRF .../ncurses-4.2 | jot -in="%r=multi_file -indextype=c;"> z@
You should now be looking at an image of the file ./multi_file_index in buffer ( @ ).
The index file has been written to your PWD, to re-use the same index file, exit and restart thusly:
$ jot -in="%r=multi_file"
Now take a look at the file-sections (C-functions) it has defined in the index:
> z. %qz=keys;For ncurses I see over 1000 listed in the keys report. Now pick any likely function name - for C the function 'main' would be a good starting point:
> main{Esc 7}The view should change to buffer ( . ) with a copy of the main() function. {Esc 7} ran macro_7 which immediately calls <<multi_file_simpleQuery>> - a jot function defined by multi_file.jot.
But hang on, I hear someone say, it's quite common for systems to have several main() routines - Quite right, the indexation process detects such name collisions and uniquifies the names by suffixing with a number (the index-file line number). The main() definition you're looking at happened to be the first one read from the index file. You can see the others by querying names matching "main" using the jot function <<multi_search_section_names>> which, for your convenience, is called by macro_8 - let's see if there are any more main() functions:
> main{Esc 8}For ncurses v4.2 I get 19 matches in total. In addition to the one we've just loaded there's 17 with numeric suffixes, these are all listed as being of type SetfsectObj. There's also a main_InText that's listed as being type FindObj, this is the hashtable entry for the image we just loaded.
If we were to query main again, rather than re-reading the same text, it just re-focuses to the original function.
Now pick up a few function names at random and load these using <<multi_file_simpleQuery>> or {Esc 7}
If you want to keep several index files in one directory, you can specify unique names for them:
$ ls -aRF | jot -in="%r=multi_file -indextype=c -index=my_index;"
and restart with:
$ jot -in="%r=multi_file -index=my_index;"
Now a Ctags-generated index
Back to First with multi_file.jot index files
Forward to The startup script
The process with Ctags is very similar to that described before (first with multi_file.jot index files), as with jot index files, the actual files are held in a floating buffer and can only be accessed using the ctags query macro ( 7 ). We will use listbufs.jot to list them. Point the ctags.jot script at an unpacked ncurses tree:
$ ctags -R <absolutePathToNcursesRoot>/*
You should now be the proud owner of a ctags file in your PWD - read this into a jot session:
$ jot tags -in=%r=ctags
You should see an image of your tags file but, hidden from view, jot has created an internal hashtable database it can use to pick up your source files for you. You can examine this with this command:
> %qz=keys;This lists the hashtable keys - each entry corresponds to a function or constant definition in the source-code tree.
Now lets pull in a source file. Selecting the function "MyMenu" at random - you can chose any of the keys listed in your hashtable-keys report:
> MyMenu{Esc 7}Pick a few more functions and constants - you can return to the keys report with this command - you previously left a query keys report in ( z ).
> zz<
P>
You can go back to the ctags-generated index with this command: <
/P>
> z.
You can return to the last-viewed source code with this command:
> z~Note that the functions ViewSave and ViewAgain will not work with floating buffers.
Unfortunately ctags.jot, by default, reads files into an internal datastructure which, in the general case, does not permit the use of the Z command for navigation between source files - each one is placed at the top of the stack by macro ( 7 ). The ctags script maintains the stack in a reasonably tidy state by removing the previous buffer object. But just because it's no longer on the stack it's still in memory, and any changes you might have made, but have not saved to the filing system, have *not* been lost.
You can list the files and their internal pathnames using the listbufs.jot script.
Running ctags.jot with the -AtoZ qualifier fixes this but it imposes a session-maximum limit of 26 files active being viewed. This is not too restrictive when, even though a source library contains hundreds of files, you will probably only want to view a few of them.
$ jot tags -in="%r=ctags -AtoZ;"
In this session, everything is as before, except that, instead of creating buffers on the stack, it assigns each new file to one of the buffers ( A to Z ). Files are allocated to buffers in turn, assigning the first to buffer ( A ), the second to buffer ( B ) ... etc.
While this scheme has the clear advantage that all files are held in simple primary buffers which can be accessed via the Z command. The advantage of the default scheme is that it can hold and access any number of files whereas, the -AtoZ scheme can only hold and access 26.
Now when you launch queries, every time it needs to read a new file, it is assigned a new buffer so you can quickly return to views of other files using the Z command. Remember, the buffer-key character is displayed at the end of the reverse-video separator line between the viewing window and the console area of the screen, it's also the last character of the jot prompt before the greater-than ( > ).
The startup script
Back to Now a Ctags-generated index
Forward to Metadata
The assignment of editing functions to keys is easily changed to match whatever editor you happen to be accustomed to - see translation of keyboard events to actions and about startup scripts. Also, it's easy enough to roll your own editor functions and attach then to keys in your own personalized startup script.
Metadata
Back to The startup script
Forward to Colour Tags
Jot is strictly a plaintext editor in the sense that it only reads plain-text and only writes plain text - anything to do with fancy fonts etc. is strictly for word processors.
It is possible and sometimes useful, to add bits of metadata to the internal representation of the text to highlight sections of text with colour or to link sections of text in some way.
In jot such metadata is implemented with tags (see about about tagged text). Three types of tags are supported by jot:
Colour Tags
Back to Metadata
Forward to Text tags
First lets add a bit of colour to the Richard III example.
$ jot ${JOT_RESOURCES}/Richard_III_Entire_Play.txt
We're going to sniff through the text identifying each new scene and colour tag those lines. First we have to define a colour pair with the %b=tagtype command:
> %b=tagtype SceneStart colour 7 5;This colour pair is white foreground on a magenta background.
Now find each new scene and add the tag with the %b=addtag command:
> m-0((v/ /r)0v/SCENE /r0ocl0ou %b=addtag SceneStart; m, m)0Notice that the extent of the colour tag is set by first defining a substring in the text.
To remove a colour tag, use the %b=remove_tag command:
> m-0f/ SCENE I./r0ocl0ou %b=remove_tag colour SceneStart;The remove tag command first checks all the details given (tag type must be 'colour' tag name must be 'SceneStart' and the start and end points of the text string mus all exactly match those of the tag or the command fails.
The colour can be used for any purpose - maybe just to add a static highlight to sections of text - but they are particularly useful when used to indicate hypertext links.
Text tags
Back to Colour Tags
Forward to Rec 15
Text tags allow the programmer to hide strings in the editors internal record structure. They can be used for any purpose but they are most useful when used with hash tables to hide keys behind the text.
Here we're going to hide the short string "This is a short string" behind the first line of the play.
Read Richard III into a new session:
$ jot ${JOT_RESOURCES}/Richard_III_Entire_Play.txt
Find the first line and make all of the text a substring:
> f/Now is the winter/ocr0ocoso#l0oro-ouNow add the string:
> %b=addtag -text=This is a short string;Now retrieve the string with query tags with the -here qualifier this restricts the report to tags directly below the current character.
> %q$=tags -here;The report should read like this:
tags -here Reporting tags at Line no. 15 Character no. 4, Buffer .
Rec 15
Back to Text tags
Forward to Mouse Events - 1
" Now is the winter of our discontent" Type text from chr 4 to 39 = "This is a short string"
Mouse Events - 1
Back to Rec 15
Forward to Mouse Events - 2
By default, all mouse events are disabled - linux users can then use all the normal X-windows selection facilities. Mouse events are enabled by setting the mouse mask - this is a bit-mapped mask selecting mouse actions that are required see %s=mousemask.
When a mouse event is encountered, it is delivered as an escape sequence which allows the programmer to define a handler for the event. A left-button-click, for example is encoded as M0004 - see the relevant key-setup file for the full list (e.g. ${JOT_HOME}/coms/unix_keys.jot).
When a left-click-event happens the editor picks up the escape sequence {Esc}M0004 to locate the mouse-click position in text use the query getmouse command this adds three items to the stack - the buffer key, the line number and character number. For this example we are just going to report these values in the console area:
> z^m-0i/M0004 opn.a$z$ oo"Mouse click in buffer %c, "lr oo"Line no. %d, "lr oo"character no. %d" pz./bTo enable just the left-click event (in linux/X-windows) we would set a mouse mask of 0004:
> %s=mousemask 0004;For windows, all mouse events are enabled together with this:
> %s=mousemask -1;Mouse Events - 2
Back to Mouse Events - 1
Forward to Hash tables
We can set up a simple menu-driven system by defining a secondary window containing clickable menu items. A simple form of popup menu can be mechanised using a jot popup window.
First define a new startup file named menu_startup.jot. Pick up the following and drop into a bourne-shell session (doubtless windows users know some way of doing this in windowsland):
$ cat - > menu_startup.jot <<endOfFile %%This jot script sets up a simple menu-driven editing environment. %% %%First Run the normal startup. %r=/home/jone/ed//coms/startup.jot; %% %%Buffer M will be the menu - define the colour tags. n.amzm %b=tagtype Button 4 7; %%Define button text. i/ /20r0b2m-0 r5i/FindAgain/ %b=addtag Button; %b=addtag -text=M_FindAgain; r5i/Find/ %b=addtag Button; %b=addtag -text=M_Find; r5i/SubsAgain/ %b=addtag Button; %b=addtag -text=M_SubsAgain; r5i/Subs/ %b=addtag Button; %b=addtag -text=M_Subs; %% %%Remove all windows from the screen, add a 1-line static window on buffer M followed by a floating window. %q~=window; f/screenHeight = /- oidol5o-z.osok %w=clear; %wm=new -height=1; %w=new -height='~ -delim; %w=refresh; %% %g0 %%Mouse-event handler. %% %%Get mouse coordinates and check for tags. ob %Q=mouse; ozono-om or ( %q$=tags -here;
f/Type text from chr/f1/"/- v/M_FindAgain/ zmm+2o#ozf'm?zmm-0 oz, v/M_Find/ zmm+2 %s=prompt Find string> ; gm- o#ozf'm?zmm-0 oz, v/M_SubsAgain/ zmm+3o#ozs'm?zmm-0 oz, v/M_Subs/ zmm+3 %s=prompt Substitute string> ; gm- o#ozs'm?zmm-0 oz, oz %x=Error: Invalid mouse click.; )
: %%Attach the handler to left-button-click events (M0004 - linux, MB1c - Windows). obz^m-0(%q=windows; f/MB1c /-?, f/M0004 /-)e0i/'0/ oz %%Enable mouse events. %s=mousemask 0004; endOfFile
This can be run by using it as a startup script:
$ jot ${JOT_RESOURCES}/l99.t -st=./menu_startup.jot
First click on "Find" and specify a search string - say "abc". Then click on "Subs" (substitute) and specify any string to replace the matched substring.
Hash tables
Back to Mouse Events - 2
Forward to Playing With Hash tables
In the implementation of hypertext links, hashtables are useful, but not essential they avoid the necessity of repeating complicated string matches for every query and, for *very* large files they can speed up individual queries - but the setup times can get excessive.
Now jot will only read simple plaintext files, so all the so the links are set up in some initialization phase. In this example we're going to add a scene-contents page to the Richard III text. This example sets up simple hypertext links between a separate table-of-contents buffer and the main text.
Playing With Hash tables
Back to Hash tables
Forward to Playing with Data Objects
Read Richard III into a new session:
$ jot ${JOT_RESOURCES}/Richard_III_Entire_Play.txt
Set up the hashtable - allocating 100 entries, in fact it needs less than 30.
> %h=create 100;Define the table-of-contents colour tag.
> n.aczc %b=tagtype TOCLine colour 7 5;Enable mouse left-button clicks, and define a mouse-event handler function.
This goes to the mouse-click position and picks up a text tag - this is the hash-table key required to look up the scene. In fact this example could have been implemented without text tags - since the contents-table entry is identical to the key hidden in the text tag. In general, however this is not the case.
> %s=mousemask 0004; z^m-0i/M0004 opozono-omor %q$=tags -here; f.Type text from.f1.".-bf1.".b-z.m0w %h=jump '$; l0/bNow sniff through the text locating each new scene, make a hashtable entry for it, add a line to the contents list and tag it with the text and the TOCLine colour.
> z.m-0((v/ /r)0v/SCENE /n.r0a$& %h=addjump '$; zch$b-ocl0ou %b=addtag TOCLine; %b=addtag -text='$; z.m, m)0Finish off at the start of the table of contents.
> zcm-0Playing with Data Objects
Back to Playing With Hash tables
Forward to Playing with data trees
Data objects are copied to and from hash-table entries and the stack. And can be used in a similar way to variables in normal programming languages. There are three data types allowed on the stack - integers, reals (floating-point numbers) and buffers.
A data entry is created with the %H=create command, values are defined using the OV command, which copies the value at the top of the stack to the object and values are referenced by the OQ command. The declaration does not define the data type but once assigned a value, all later assignments must be of the same type (integer, real or buffer)
Here's a few things to try:
> %h=create My_int; ol123 ov/My_int/We've defined the hashtable entry pushed the number 123 onto the stack and then popped that stack entry to define the value of data object My_int. At any time we can redefine the value with another OV/My_int:
> il456 ov/My_int/Now that they've been defined their type is also defined so this will fail:
> ol123.456 ov/My_int/The process for real numbers is pretty similar but, for buffers we might chose to use the %D command to define a new buffer at the top of the stack:
> %h=create My_buf; %d~=This is the string in My_buf; ov/My_buf/Or, we might chose to use an abstraction to define the buffer - something like this: n. ... a~
Playing with data trees
Back to Playing with Data Objects
Forward to Functions
Since jot allows buffers to dangle off the hashtables of other buffers, there exists the possibility of creating huge trees of unlimited complexity. Well that's probably not a good plan, but there's a lot to be said for building relatively modest trees.
In order to facilitate navigation around such trees there's a path-descriptor syntax that can divine any data point in trees of any complexity. Given that the starting point is always a single (frequently but not necessarily alpha) character and the remaining path elements, each separated by some system-defined character. The path-specification syntax being: [<bufferKey>]=<pathElem1>[|<PathElem2>[ ... ]]
The hashtables are created one at a time. in this example we're creating three levels of hierarchy - "Top", "Mid" and "Bot" dangling off the top-level buffer Q:
> zq > %h=create 100;This creates a hashtable big enough for at least 100 entries in buffer Q.
Next, we have to create the hashtable entry "Top" in our freshly-minted hashtable:
> %h=data q=Top;Then we have to set up a dummy buffer for the next level:
> %d~=Top dummy; ov/q=Top/Set up the next-level buffer and create a new hashtable there:
> %h=create 100 q=Top; %h=data q=Top|Mid; %d~=Mid dummy; ov/q=Top|Mid/Finally create the bottom level:
> %h=create 100 q=Top|Mid; %h=data q=Top|Mid|Bot; %d~=Bot dummy; ov/q=Top|Mid|Bot/Then, if we want to do hashtable operations here, it had better have a hashtable:
> %h=create 100 q=Top|Mid|Bot;Finally, use the listbufs.jot script to list the data tree we've just created:
> listbufs{F2}In addition to the free we've just created listbufs will also show some data objects in the ( ' ) buffer - these are created by the startup.jot script.
Take a look at the test.jot script for an example of a very deep tree or the fake_vim.jot and fake_emacs.jot scripts for more practical examples.
Functions
Back to Playing with data trees
Forward to Working with ide.jot
Jot uses hash tables to implement function calls. By convention, function names appear at the head of the routine code, enclosed by double angle brackets:
<<MyRoutine>>%%This routine just says hello world and exits. %m=Hello world.
These are held in a buffer known as a repository, by convention this is the ( * ) buffer - but any other will work. A hashtable target-point tag is added to the end of the function-name line. This tag is important for two reasons:
There is a special function, provided by the normal startup script, that registers and tags new functions - it's AddNewFunctions. This function registers new functions in the code-repository hash table. We're going to do this for <<MyRoutine>>:
> %G@ > <<MyRoutine>> > %%This routine just says hello world and exits. > %m=Hello world. > : > %h=call AddNewFunctions;Now call the routine:
> %h=call MyRoutine;It sends the message "Hello world" to the console.
Note there is no "return" or similar command - control must be allowed to trickle down to the end of the routine.
Working with ide.jot
Back to Functions
Forward to The hello project
ide.jot is a simple IDE for gdb and winedbg. It can support projects with a single source file or it may be combined with ctags.jot to support projects with source libraries indexed with ctags.
There is a demonstration development tree at ${JOT_RESOURCES}/IDE, this contains two subdirectories - work, which contains various project files and a startup.jot and a directory ed which contains only a hello.c source file - guess what this does.
The ide.jot file is run from the startup script, it sets up a simple menu bar containing the following buttons:
First copy the projects tree from the resources to somewhere convenient to you.
$ cp -R ${JOT_RESOURCES}/ide .
There are six projects supplied in the subdirectory ${JOT_RESOURCES}/ide/projects
The hello project
Back to Working with ide.jot
Forward to The ide_hello project
The ide_hello project
Back to The hello project
Forward to The tree project
The startup file re-reads your project notes into buffer ( S ) and reads just one more file - the source code, and parks it in buffer ( . ).
You can compile it with gcc or use the Makefile.
Fire up a jot session using the ide_hello-project setup:
$ cd projects $ jot ide_hello
The tree project
Back to The ide_hello project
Forward to The ncurses project
This is a simple IDE example of a source tree using an ctags-generated index file. If you've not already done so, copy the example projects tree - see The hello project
$ cd ide/tree $ ctags -R * $ cd ../projects $ jot ide_tree
The startup script in buffer ( F ) contains pathnames which may need adjustment.
The ncurses project
Back to The tree project
Forward to The jot project
This IDE project uses a real code project - ncurses.
If you've not already done so, copy the example projects tree - see The hello project.
First cd to the ncurses directory then download and unpack an ncurses-4.2 (although any version will probably do). Note that ctags.jot must find the tags file in the ncurses root directory and that it requires the pathnames to be absolute.
$ cd <path>/ncurses-4.2 $ ctags -R `pwd`/*
Now edit the startup.jot file - in the tags_curses project find the line:
%i.=/home/jone/Downloads/ncurses-4.2/tags
change the pathname to match your installation.
$ jot ide_curses
Pull the file containing, say, the MyMenu function.
> MyMenu{Esc 7}The jot project
Back to The ncurses project
Forward to The debugger
This sets up the editor for jot-code development. This requires a copy of the jot source code in ed/source - If you've not already done so, copy the example projects tree - see The hello project.
The startup.jot reads several files into various buffers in the jot session, where they are easily accessible using the Z command.
The debugger
Back to The jot project
Forward to Adding an explicit break-point to a macro
Here we're going to run through a few typical debugging methods utilizing the various debugging features offered by jot.
This is a broken version of that little profiling macro from an earlier section:
> %g3%%Copy text to @ and change all alphas to lower case. m-0n.m0r0a@&z@ m-0(q/A-Z/c, r, m)0
%%Place each word on a separate line then sort them alphabetically. m-0(q/a-z/(q//r)0b, rr-(q/a-z/\e)0, j)0 %b=sort
%%Finally, count up instances of each word %%m-0 (r\j)0 r-0(n.r0a$&ol1m(v'$r0v-'$o~k)0 m-oo/%5d - /m)0 m-0 (r\j)0 r-0(n.r0a$&ol1m(v'$r0v-'$o~k)0 m-oo/%5d - /m, m-0)0 :
The difference is this one runs for much longer and then exits with a stack overflow message:
> '3...{Stack overflow (line 9 of buffer 3)}m-0 (r\j)0 l0(n.r0a$&[ol1]m(v'$r0v-'$o~k)0 m-oo/%5d - /m, m-0)0
(The highlighting in the message indicated with square brackets)
Oh dear, it looks serious - how are we going to fix this? First we might find it useful to know which line it's failing on. Well that's easy the message says line 9. We can also see that the failing command was trying to load a zero on the stack but that's not the command that's giving us grief. As usual the error message points to the smoke not the fire.
We can see at a glance that that the problem is the addition of ", m-0" at the end of the final loop. This means the loop will *never* exit since m-0 is guaranteed never to fail.
Adding an explicit break-point to a macro
Back to The debugger
Forward to Skipping past a block or call
To see what's going on in a complicated command sequence, you could do worse than single-step them in the jot debugger. This can be set to single-step through the commands as you hit the {Return} button.
When you run your command sequence, the debugger halts at every jot command, dumps the contents of the stack and prints the current record, in the console area. When it reaches a break point it prompts with this string:
Debug Command>
To continue running normally, we have to set the trace vector back to zero.
Debug Command> %s=trace 0
Which lets it run on to the next explicit t command.
To avoid typing all that in every time, there's a hotkey set up by the startup script:
Debug Command> {Esc q}
To exit the debugger hit {Ctrl+c} at the debugger prompt.
To see all of the trace text you may find it helpful to reduce the window size so that more of the screen is dedicated to the console display (assuming your terminal is 40 lines or more):
> %w=clear; %w=new -height=20 -delim;This changes your window size to just 20 lines, for a 40-line xterm the startup script sets the window size to 39 lines, including a one-line terminator. Leaving just 1 line for the console area. After this hit return a few times to see the effect of the new window setting.
First go to the start of the Richard III sample an type t, or insert a t command into your command sequence:
> zq m-0 o@ tNow hit {Shift+RightArrow} - this is a complicated function because it has to deal with tabular and normal text.
Hit {Return} a few times while looking at what's going on in the console area - you will see it plodding through the commands of the <<WordRight>> function and displaying the stack and the current line at each step.
Skipping past a block or call
Back to Adding an explicit break-point to a macro
Forward to Setting the command counter
Often it would be useful to step over a complicated function or maybe a script or a block. The jot debugger implements this using the %s=traceskip command.
As execution of any block, macro, function or script begins a special run-level counter is incremented. When the structure exits, the counter is decremented.
The traceskip command takes an optional parameter, this is the run-level at which it is required for tracing to resume. This is a simple numeric value indicating the desired resumption run level relative to the current run level.
Let's try this out:
$ jot ${JOT_RESOURCES}/Richard_III_Entire_Play.txt -in="%w=clear; %w=new -height=9 -delim; ( t ( (rr-, m) rr- ( %r=age; ( r )0 ) m )0 m-0)"
The -init command string includes a script call embedded in a few blocks. The t command initiates single-stepping and, because age.jot is fairly long-winded and is assumed to be working, we might like to skip past this script. To clarify the display, the window size has been reduced giving a much bigger console area.
As we might expect, execution has halted at the open-brace following the t command.
Dabbing the {Return} key steps us on to the start of the next block containing the sequence "rr-, m"
> {Return}Keep on dabbing {Return} until the debugger cursor has reached the %r command. At this point, the debugger will go chasing down the age.jot rabbit hole and, in the fullness of time, we might step our way through this script.
To suspend tracing (and that includes breakpoints) for the duration of this script we might type in the full command %s=traceskip 0; but, to save you all that typing, this will suffice:
> 0{Esc q}The parameter (0 in this case) is passed on to the %s=traceskip command. It says you want to suspend tracing until run level gets back to it's current level.
If we had wanted to suspend tracing until some outer block had finished we could have given it a value of 1 or 2 - depending on which block.
Setting the command counter
Back to Skipping past a block or call
Forward to Backtracing
Now, when debugging a long complicated macro or script, it may be more useful delay the trigger until we're getting close to the point where it goes wrong. This is the definition of a macro similar to one we've already looked at in the macros section:
Well, the problem is probably somewhere in the loop - lets start off by putting an explicit breakpoint in it:
> z3m+9f/n.r0/i/t /Line nine of the macro should now look like this:
m-0 (r\j)0 l0(t n.r0a$&ol1m(v'$r0v-'$o~k)0 m-oo/%5d - /m, m-0)0
So, re-spin it (first reset the stack):
>o@ z.'3After hitting {Return} a few (hundred) times we we don't seem to be getting very far. So let's try delaying the explicit debug call by a few zillion and restart it. But first we've got to get out of this {Ctrl+c} will do that:
> %s=commandcounter 1000000 > o@ z. '3It crashed again but we can now find out how many times it went past the t command by looking at the current value in the command counter:
> %qa=systemWill tell us where the command counter got to - 946974 in this case. Some arithmetic will extract the number we want in the command counter. This sequence will work it out for us - note the new value (53026) we will need this if ever we re-run the debugger with this setup:
> o@ %qa=system; f/Command counter = /-oid ol1000000 o- ol0 os o- %s=commandcounter '~Command counter was 946974, now set to 53026
Re-spin it and it reaches a breakpoint at the start of the fatal iteration.
> o@ z. '3Backtracing
Back to Setting the command counter
Forward to Line 1 of macro C
Backtrace reports can be useful when diagnosing problems and can be used to show the call stack when debugging a script or macro command. Jot gives a few diagnostic clues as to where a failure occurred, unfortunately, an explicit message pointing to the last command is not one of them. This is because jot has no way of identifying unhandled failures until it has already unwound the call stack - and by then all diagnostic information is destroyed. One useful clue it does give is a command counter.
The problem with backtracing is that failures occur hundreds of times in the operation of a normal jot macro command, the interesting one is the one that unexpectedly causes the entire macro to fail.
Fire up a jot session with a bigger than usual console area:
$ jot ${JOT_RESOURCES}/l99.t -in="%w=clear; %w=new -height=15 -delim;"
Backtracing is turned on with the Trace_Backtrace bit of the trace-mode bitmask. Try turning it on for a while and see what happens:
> %s=trace 7804;That's turned on backtracing along with:
It has selected only Trace_Failures as a trace point - this triggers the specified trace activity (Trace_Source, Trace_Print, Trace_Stack and Trace_Backtrace) immediately after any command fails.
Now set up a few simple macros - notice macro c is pretty-much guaranteed to result in a failure:
> %da=r-0rr-rr-rr-rr-\\'brr-rr-rr-rr-rr-; > %db=rr-rr-\\'crr-rr-; > %dc=rr- p r999rr-; > 'aIn the console area, along with lots of other chatter, you should see something like this:
Line 1 of macro C
Back to Backtracing
Forward to Line 1 of macro B
rr- p [r999]rr-
Line 1 of macro B
Back to Line 1 of macro C
Forward to Line 1 of macro A
rr-rr-['c]rr-rr-
Line 1 of macro A
Back to Line 1 of macro B
Forward to Line 21 of console c
r-0rr-rr-rr-rr-['b]rr-rr-rr-rr-rr-
Line 21 of console c
Back to Line 1 of macro A
Forward to Setting command-counter breakpoints
['a]
The top line, as is the convention with backtracing, is the line of code and call frame nearest to the error, the next one down shows how that code object was called ... etc.
The top line tells us that it was the r999 command that was the culprit - well no surprises there.
The 2nd. line down says the macro in buffer ( C ) was called by a macro in buffer ( B ).
...
Setting command-counter breakpoints
Back to Line 21 of console c
Forward to The trap_failure.jot script
Every time a interactive command is issued, a command counter is reset, this counter then is incremented as each primitive command is processed. When an unexpected failure causes an early exit from a function, this counter can be retrieved and can be used to re-run the function so as to stop at the previously-failing primitive.
Unfortunately, a simplistic approach to reading this counter will not work because the simplistic approach will require a new command line to be entered destroying the clue. There are two ways of finding the command counter value:
As outlined in %s=commandcounter, we can trap execution at some predetermined point in the overall flow, specified by of a command count. The number of commands to allow is normally derived from the state of the command counter at the point of failure in some previous run. Note, however, that some functions require initialization and that some complicated initialization commands involve conditional statements. Thus the final state of the counter can change.
The trap_failure.jot script will take care of the command counter but it's left to you to ensure that initial conditions are the same for both the failed run and the trapped run. It has an optional -init sequence which is run before initializing the counter.
First we'll run through a trivial example - a command sequence that attempts to send the cursor past the end of a line. The Richard III text contains no line longer than 80 characters.
$ jot ${JOT_RESOURCES}/Richard_III_Entire_Play.txt> %s=verbose 13;
With this set, each failure message also includes the command count e.g. the sequence:
> m=2(rr-)1000(r)999(rr-)1000will result in this report:
{Command-sequence failed. (3120)}m=2(rr-)1000(r)999(rr-)1000the sequence failed at command no. 3120, if we want to trap this command we'd use this sequence of jot commands:
> %s=commandcounter 3120; m=2(rr-)1000(r)999(rr-)1000This re-launches the command sequence but after 3120 steps it triggers a trace action (see %s=tracedefault), the default action is to break execution at every primitive, backtrace and report the state of the current buffer.
As we might have expected, the cursor is at the very end of the line and the next R command is guaranteed to fail. In real-life examples, the outcome is not always as easy to predict.
The trap_failure.jot script
Back to Setting command-counter breakpoints
Forward to Debugging -init sequences
The trap_failure.jot script is designed to automate the process, it also allows a separate initialization sequence. We will use it now for our simple example.
> trap_failure (rr-)1000(r)999(rr-)1000 -init=m=2{F2}The command sequence "m=2 %s=commandcounter 3119; (rr-)1000(r)999(rr-)1000" appears in the console area - hitting return will launch it.
Since, in real-world debugging, the code generally goes wrong sometime before the final catastrophic failure, we might set the trap a bit earlier than 3120, this can be done by editing the command string generated by the trap_failure script. Once again launch trap_failure:
> trap_failure (rr-)1000(r)999(rr-)1000 -init=m=2{F2}now edit the command string - see about command editing, with the trap_failure-generated command line in the console area.
> {Esc c e}You're now in a command-history report, now change the 3120 to something a bit smaller - maybe 3100, then finalize the command-editing session with:
> {Esc c g}You're back to Richard III and the modified command string will appear in the console area.
The trap_failure.jot script does all this by running the function and handling the final error - the handler picks up the state of the command counter from a query system report and pushes the command string into the console area. This gives you you an opportunity to adjust the count. You can adjust the counter setting using CmdEditStart and CmdEditGo.
Debugging -init sequences
Back to The trap_failure.jot script
Forward to Trapping on {Ctrl+c}
Frequently, the most convenient way of debugging complicated scripts is to launch them from the -init sequence. We can still use the command counter but the process is slightly different.
This is an example of a failing script. It's the main jot regression test, and we're going to make it fail by nobbling the test file it uses.
$ jot ${JOT_RESOURCES}/t.t -in="m9em-0 %r=test"
Exit the session with %a, it fails because the test file was nobbled with the m9e commands. Now to get the test counter, add the else sequence "%s=verbose 13; %a;"
$ jot ${JOT_RESOURCES}/t.t -in="m9em-0 %r=test;, %s=verbose 13; %a;"
With this modified -init sequence, the failure of the test.jot script was handled by setting the verbose vector and abandoning the session.
On exit it should, instead of issuing the message "Edit abandoned" we might see something like "(499)Edit abandoned". This tells us the command counter was 499 at the point of failure. Note that the %r=test command *must* be terminated with a semicolon now that more commands follow.
Exit this session and relaunch thusly:
$ jot ${JOT_RESOURCES}/t.t -in="%s=commandcounter 495; m9em-0 %r=test"
This stops it just a few steps before it fails.
Trapping on {Ctrl+c}
Back to Debugging -init sequences
Forward to Coding examples
If your code disappears down an endless-loop, you can set the command counter and then re-run to the same point as described in Setting command-counter breakpoints. This is a very good way of getting to the exact point where something interesting is about to happen but it's setup is a bit long winded.
A simpler way is to set the Trace_Interrupt bit (see %S=trace) and then the {Ctrl+c} interrupt enters the jot debugger. You may prefer to have this set up in your startup.jot file if you are a jot debugger frequent flyer. With this bit set, a {Ctrl+c} interrupt will, instead of immediately exiting it's current command stack, will enter the debugger and you can single-step your code.
In this state, you will have to explicitly request the call stack to be unwound by giving the X command (typically x0 to exit all frames. Here's an example of an endless loop involving two commands.
$ jot ${JOT_RESOURCES}t.t -in=" %s=trace F880; (r r-)0"
After running the startup script the editor locks up as it enters the endless loop. In this case, though, we've set the Trace_Interrupt bit (0x0080) and it drops into the debugger prompt loop without exiting the init sequence.
Coding examples
Back to Trapping on {Ctrl+c}
Forward to Using %E in interactive mode with %P
Using %E in interactive mode with %P
This uses the unix od utility as an ersatz interactive process.
$ jot -st -in="%w=new -height=20 -delim; %eq= -interactive od - -cw1; %pq=abcdefghi; %pq -timeout=1 -waitfor=m-0m;"
Back to Coding examples