You don't need to remember all these commands!
They're easy to find in the in-app help, which you can open by running
M-?
(which probably means Alt ?
, unless you use a Mac).
Read this just to get a sense of what's possible.
In fact, this documentation might go stale, describing keyboard shortcuts that don't work. That is less likely for the in-app help, which is somewhat self-updating.
The UI lets you load, save, add to, search for, and navigate your data, as well as choose how it is displayed.
The text editor in Hode is extremely simple. To enter a complex expression into Hode, I prefer to write it in another application (Emacs), then copy and paste it into Hode.
If you ask Hode to overwrite a big beautiful graph with a tiny stupid one, Hode will obey.
I suggest using version control software to back up your data. Hode uses a simple, human-readable format for saving to and reading from disk. This means it works well with Git, or anything like it. Each expression corresponds to a unique file, making the diffs between versions of your data readable.
Call stack run
from the command line.
Call stack ghci
from the command line.
Now, from within GHCI, you can:
-
Call
st <- ui
to start the UI. This way, once you exit the UI,st
will be an object of typeSt
(the state of the app), which you can inspect and mess with. -
Call
uiFromSt st
from GHCI, wherest
has typeSt
, to provide your own initial state to the app. -
Call
uiFromRslt r
, wherer
has typeRslt
, to provide your own initial graph to the app, and otherwise use all the default values.
I have tried to use Emacs terms as much as possible.
The app always shows the main window
,
and sometimes at the bottom, it also shows the command window
.
Whenever the command window is showing, you are in command mode
.
This is true regardless of what is shown in the main window.
If the command window is not showing,
then the mode
you are in is determined by what is in the main winndow
.
For instance, if the main window
is showing the subgraph buffer
,
and the command window
is hidden, then you are in subgraph mode
.
Together, the current mode
and submode
determine what commands are available.
Not every mode
has submodes.
For instance, currently the subgraph mode
has two submode
s:
primary
and order
(described below),
but the other mode
s don't have submode
s.
Although this document might go stale,
you can always check the interactive help (by pressing M-?
)
for an up-to-date list of available modes and submodes.
Show or hide the command window with M-c
(i.e. probably Alt-c
, unless you use a Mac).
When the command window is showing,
anything typed without using a special modifier key
will modify the text in the command window.
Once you have typed a command,
execute it by pressing M-x
.
A subset of the Emacs (and Bash)
keyboard shortcuts are available in the command window.
Press C-a
(that's probably Control-C
)
to put the cursor at the front of the line.
Press C-k
to delete everything at or after the cursor.
The main window can show a few different kinds of things.
Most of the time,
the main window will display a subgraph buffer
.
There can be multiple subgraph buffer
s open at the same time,
each (probably) corresponding to a different search.
Whatever the main window is currently showing,
you can switch to the current subgraph buffer
by pressing M-g
.
Sometimes you wiill want to switch between subgraph buffers.
Switch to the buffer select buffer
to do that.
The buffer select buffer
is described below.
When an error happens,
the main window will automatically switch to the error buffer
.
There are lots of ways to escape the error buffer --
for instance, by switching to the subgraph buffer,
as described above.
A subgraph buffer shows a subset of your data.
It's initially populated by running a search (something starting with /find
)
in the command window.
The UI displays expressions from your graph using the Hash language.
When you first run a search,
everything it finds is displayed left-justified.
Thereafter you can use keyboard commands
(e.g. insert hosts
, described later in this document)
to complicate that view,
inserting things that are justified farther to the right,
creating a multi-level view-tree
.
Here's an example of a subgraph buffer's contents, after such complication. (The actual display is in color, which makes it more readable. The column of numbers at the far left is described in the next section.)
3 6 haskell
_ #of it
1 7 stack #of haskell
1 22 extension #of haskell
_ #using it
1 89 benchmark #using haskell
0 666 java
Each expression is stored at an address
in the graph.
By default, that address is displayed to the immediate left of the expression located there, in a different color.
For instance, in this example,
the expression "benchmark #using haskell" is at address 89.
When you're in subgraph mode
(i.e. you've hidden the command window),
those addresses can be toggled off and on by pressing a
:
3 haskell
_ #of it
1 stack #of haskell
1 extension #of haskell
_ #using it
1 benchmark #using haskell
0 java
Note that some of the rows of the example display have no number in the column at the far left.
That is because they are not expressions in the graph.
They are used, rather, to group the expressions below them.
Where they say it
, it
refers to their immediate parent --
e.g. in the example above, it
means "haskell".
If "haskell" was a much longer phrase,
you might wish that the display did not repeat it.
In subgraph mode
,
you can toggle whether descendents restate the expressions they are descended from by pressing A
.
For instance, the above example would become this:
3 6 haskell
_ #of it
1 7 stack #of @6
1 22 extension #of @6
_ #using it
1 89 benchmark #using @6
0 666 java
Rather than "haskell", the formerly redundant subexpressions now read "@6" -- that is, "the expression at address 6".
(Note that if you're reducing redundancy this way, you probably don't want to have disabled the display of addresses to the left of expressions.)
There's a column at the left with numbers in it. For each expression at the right, this column indicates how many expressions contain that one. For instance, if your data includes "cats", and "cats #eat bugs", and "cats #avoid water" (and nothing else), then the number 2 would appear in the hosts count next to "cats", because two expressions contain it.
By default, the hosts count is the only column shown.
If you want to hack around, you can change that.
Just change the _columnHExprs
field in the app's St
.
Commands in Hode divide come in two flavors.
Language commands
require you to type a statement into the command window,
and then execute it (M-x
).
Unlike language command
, keyboard commands
are not a two-step process:
you press a key (or key combination) and something immediately happens.
Language commands can be executed any time you are in command mode
(which you can toggle with M-c
).
The keyboard commands that are available depend on what mode
and, perhaps,
submode
you are in.
These are entered in the command window, and executed with M-x
.
Type something like /load path/to/my/data
.
(It has to start with the symbol /load
, followed by a space.)
If there are .rslt
files in the path you entered,
they will be loaded into Hode, flushing out whatever was previously loaded.
Subfolders are ignroed.
Same idea:
/save folder/subfolder/subfolder
PIFALL: Saving does not first erase the contents of the folder. This is a bug. If you load your data, and then change the address of an expression, or delete an expression, and then write your data to disk, the old expression at the old address will still be there.
Write /replace
(or /r
),
followed by the expression's address,
followed by what should be there.
For instance, /replace 3 x # y
would replace
whatever used to be at address 3
with the expression x # y
.
Replacement destroys the old expression. Any "host expression" (or "superexpression") that used to contain it now contains the new expression instead.
Replacement does not, however, destroy the old expression's sub-expressions.
This has security implications. For instance, if your graph used to contain the statement, "I #enjoy pornography", and you replaced that with "I #enjoy ethnography", your graph still contains the word "pornography".
Deletion is only possible for a top-level expression -- that is, an expression that is not a member of any other expressions. (If you deleted "seaweed", what would happen to "I #(must buy) seaweed"?)
The syntax is /delete a
or /d a
, where "a" is the address of the expression to be deleted.
The documentation on the Rslt and Hash provide details. Here's a brief refresher:
/add dogs
/add dogs #eat grass
/add /addr 1 #because /addr 2
/add /addr 1 #is (cheaper #than stan's bike) ##(and therefore) /addr 3
See the documentation on Hash for details. Here's a brief refresher:
/find bob
/find /addr 1
/find bob #likes (pizza #with pineapple) ##because /_
/find /eval bob #likes pizza ##with pineapple ###because /it)
-- Returns only the reason, not the full "because" relationship.
/find bob #likes /_ /|| bob #dislikes /_
-- Every #likes and every #dislikes statement with bob on the left.
See the documentation on order.
This is kind of a strange thing to do. You probably won't ever need to. However, just in case:
To move the expression at address a
to address b
, type this:
/move a b
.
If b
was already occupied, whatever was there is now located at n+1
,
where n
was the maximum address in your graph before the /move
.
One result in the subgraph buffer
is always "focused".
It shows up in a different color.
Similarly, one buffer in the select buffer buffer
is always focused.
These shortcuts move that focus around.
PITFALL: There are two separate kinds of focus.
Every subgraph buffer has a focused result;
it's the one with a different color scheme.
Exactly one of the subgraph buffers is itself focused;
it's the buffer with a different color scheme in the select buffer buffer
.
The only subgraph buffer
you can ever see is the focused one.
Changing which one is focused is what the select buffer buffer
is for.
Once you've typed something into the Command window, do this to run it.
Show the currently focused subgraph buffer
: M-g
Show the select buffer buffer
: M-s
Show the command history buffer
: M-h
The focused result in the subgraph buffer might be a member of other relationships. If it is, this displays those relationships "under" it (that is, below it and slightly to its right).
The focused result, if it is a relationship, consists of members. This displays each of those members under it.
Repeated use of the previous two commands can lead to a very cluttered view. This can clean it up. This does not change your graph, just the view.
This creates a new subgraph buffer showing exactly one thing,
the expression that was focused in the previous buffer.
The previous subgraph buffer continues to exist,
and in the select buffer buffer
,
the new subgraph buffer
is a child of the old one.
Suppose you often find yourself running
/find alice /| bob /| chris
You can add that search as an expression to your graph.
Once it's in your graph, when it has focus
(see the section called "Move focus" earlier),
you can run it by pressing S
.
The search results will be inserted underneath it.
There are many ways you could add that search as an expression in the graph. Here is the simplest way:
/add "alice /| bob /| chris"
Note that the query has been wrapped in quotation marks.
(Otherwise Hode would try, as usual,
to interpret the |
symbols to mean "or", and it would get confused,
because it's trying to add a single thing, not search for a few things.)
After running the above expression, your graph will contain the expression
"alice /| bob /| chris"
Suppose your graph had an error, and you had to change bob
to rob
.
Every expression that bob
was in now says rob
instead.
But the search you encoded did not include bob
--
it contained instead the string alice /| bob /| chris
.
So now the search is broken --
it will continue looking for bob
, not rob
.
Here is a better way to encode the same search:
/find alice # "/|" # bob # "/|" # chris
Each term in the search -- the words and the /|
symbols --
are now separated by #
marks. When you run the search,
the expression is "flattened": the #
marks are stripped away,
and the results joined together (with spaces in between).
This way, when you press S
, the search that gets run is the same:
alice /| bob /| chris
But since each term in the search has been encoded as a separate entity,
Hode "knows what they are". If you change bob
to rob
,
it will change in the search too.
(You don't have to wrap alice
or bob
or chris
in quotation marks,
because they contain no characters that Hode treats specially.)
This copies everything in the currently-displayed subgraph buffer, even if it does not all fit on the screen.
These are described in the docs on order and transitivity.
From the buffer window you can create new buffers
and switch between them by moving focus (as described above).
Once you've moved focus to the buffer you'd like to see,
you can switch back to the subgraph buffer with M-S-r
.