Leo Editor
leoeditor.com
leoeditor.com
It's a very good and well thought out program, it's a bit like a cross between emacs org mode and python programming environment (rather than lisp) geared towards literate programming but very useful for other kinds of applications.
I'd love to see a 'Google docs' style multi-user version of it, that would be an awesome tool, especially if it would be self hosted.
We really will do that rewrite one of these days though, especially with more than one job on the go at once the system will start to show its limitations.
Even so, for a three day hack it has done remarkably well.
This sounds like something that would be more than interesting enough for me to want to read, quite apart from the quality or complexity or ingenuity of the code itself. A nice write up isn't necessarily one that was planned as such at inception.
Side note: it uses a bunch of keyboard short-cuts to rearrange the tree by moving nodes around and JS absolutely sucks are reliably capturing ctrl-key combinations. Highly frustrating.
Long story short (and without the code):
The application presents a tree to the user, parts of which can be copied, each node in the tree is internally referenced by an ID which allows for multiple nodes having the same name attribute. Besides the name attribute there are tags, source (handy to keep track of where you found stuff), an answer to the question associated with that node, an advisory and a bunch of flags and priorities.
The layout is three panes, a top one with some links for commonly used functions and a search bar, the left hand side gives the tree and the present location in the tree and the right hand side shows all the attributes of the current node.
It features import and export in XML format of the whole tree or parts of it, the ability to attach pdfs and images to nodes (the images are shown inline in the parent node), to attach notes to nodes and to export to a different editor for report writing purposes (usually open office).
For example the top node for accounting is like this:
#@killcolor
# accounting
from datetime import date
import pprint
import math
<<defs>>
year = 2006
<<2006>>
inc_year()
<<2007>>
inc_year()
<<2008>>
... more data
inc_year()
<<2018>>
inc_year(0) #update certain yearly balance records without
advancing
def runacct(argv):
if len(argv) > 1:
if argv[1] == 'q':
transquery(argv[2].upper())
elif argv[1] == 'g':
groupquery(argv[2].upper())
elif argv[1] == 'h':
holdingquery(argv[2].upper())
elif argv[1] == 'm':
if len(argv) == 3:
monthquery(int(argv[2]))
else:
monthquery(int(argv[2]), int(argv[3]))
elif ... many other query options
else:
balancequery()
if __name__ == '__main__':
from sys import argv
runacct(argv) class acct(object):
# bank and brokerage account
allacct = []
def __init__(self, name, balance, holdings=None):
self.name = name
self.balance = balance
self.holdings = holdings
self.xferamt = 0
self.accum = 0 # used to track cumulation ad hoc values
acct.allacct.append(self)
def buy(self, sec, amt, cost, day):
rec = trans(('buy', sec, amt), -cost, day, self)
self.balance -= cost
if not self.holdings.has_key(sec):
self.holdings[sec] = [0]
self.holdings[sec][0] += amt
self.holdings[sec].append(rec)
......
class trans(object):
# transaction record object track cash invovled in each transaction
allrec = []
def __init__(self, t, amt, day, where):
try:
self.type = t
self.amt = amt
self.date = date(year, month, day)
self.where = where
trans.allrec.append(self)
except Exception as err:
print t, amt, year, month, day, where
raise err
Then for each data line I just do any of the following: SOMEACCT.buy(...)
SOMEACCT.sell(...)
SOMEACCT.credit(...)
SOMEACCT.debit(...)
SOMEACCT.xfer(...)
# classified by tax categories:
SOMEACCT.int(...)
SOMEACCT.div(...)
SOMEACCT.fdiv(...)
SOMEACCT.mint(...)
SOMEACCT.mdiv(...)
Then it is easy to query and do computations in any way one cares to write a function to do.The good: If you can wrap your head around it and spend a fair amount of time learning it, it is quite useful, and the claims on the web site no longer seem crazy. It's not my primary editor, but I can see I'll use this a lot (primarily an Emacs guy).
The bad: Very poor documentation. A lot of the stuff on the site is outdated (so examples won't work). In my experience, people on the mailing list will help, so it makes up for the poor docs - but it is kind of off-putting. There's a ton of stuff it supports that are mentioned nowhere in the docs.
Some hints: Learn how settings work, and dive into all the settings - you can do this from within Leo. You'll learn a lot more about Leo's capabilities that way (as well as make small tweaks to the pretty ugly UI). Changing a setting doesn't go into effect immediately - for that I think you can do:
M-x reload-settings (honestly forgot the command).
Some settings, though, involve quitting and restarting.
Also, it's not really a great editor. Its power comes from nodes and scripting. So become very comfortable with nodes, and try to learn scripting immediately. I'm still a beginner at the latter, and sadly the docs just suck. So I slowly try, ask, learn more, make my own notes, etc.
If I keep it enough to become much more knowledgeable, I'll probably end up writing a proper guide on using it.
It very much is similar to Emacs in the sense that everything is a command/function. So you can reprogram it to do whatever you want.
I used to use Leo for notes on everything I was working on. The killer feature for me was the tree outline pane could clone nodes. So I could have one subtree of say Projects, another of say my Jira tickets, a third on Talks and Blog Posts. And then have clones of the current ones all together in a subtree called Current. I would adjust their order each morning as my prioritised To Do list for the day.
More recently, I have tried switching to orgmode. Some aspects are great. But I really miss Leo's tree pane 'table of contents' and its clonable nodes.
At work we are not allowed to run random software; every package needs to be registered, source security-tested, compiled from source in house, put in an internal repo, and then installed from there. So while at home I could do 'pip install leo', at work it was a mess of tracing dependencies (Qt), getting them registered, etc, etc.
Plus at work, someone else had gone through this pain for Emacs and orgmode.
On the good side stands the ability to have an programmable outline, paired with a good enough editor to handle the content of nodes. Then there also directives, which are basically special commands for inline-usage. Things like @wrap to wrap lines, or @language <value> to define activate language-specific handling for the following code. @language is especially useful because you can combine several in one node. Finally there is also the relativ open ability to customize things with python. All of this combined a regular workflow I still use with Leo is to create a node with several @language-blocks on a node. One for code, one for data, one for Documentation. Then call a selfmade-function which extracts the code and data and executes it and save the result in a new node in the outline. Very useful to transform or generate data on the fly. There are also directives to load/save external files, with support for some fileformats to automagically handle the outline.
But then again, on the bad side, as a dev I must say the whole projects has a horrible stench of foul code and ugly design. There is a huge amount of features which either work bad, don't work at all or even work in harmful ways (dataloss). The codebase is just a ragtag-compilation of random ideas from people which seems to have no clue about proper software development, and who are even proud to have come up with some shit they consider as smart. For anyone who wanna try out this software: don't except to much, and prepare for many hateful corners and a steep unnesseccary learning-curve. And save your data! Often.
> “Word outlines are very useful. But Leo makes Word look like a clunky toy.”—Joe Orr
Well, yes. Any text editor would make Word look like a clunky toy, because Word is a word processor. They don't do the same things, they aren't aimed at the same audiences, and they evolved different UI conventions because of that.
That nitpick aside: It being written in Python is nice, and the fact outlines give your document something like a DOM which is accessible in a Python object tree is nice. It might be possible to massage this into something almost as nice as macros for languages like C# or Java.
I've used org-mode for about a year and a half and have found it helpful to to my productivity and feeling put together. I can see the potential for benefits to a team, but not many people want to learn emacs for a job if they don't already use it.
Your project should ideally be independent of the IDE being used.
The good: Leo provides rapid access to understanding the complexity.
The bad: Leo XML file format is collaboration hostile, since resolving git conflicts in its multi-megabyte XML file is out of the question.
The ugly: I've got perl code to translate the XML file to and from a directory of several thousand small files, one per Leo node, and far more git-conflict friendly.
The worst: the version of Leo on which we're stuck used "sentinels" - specially formatted comments - to keep Leo's structure of the file in sync with external changes to the file. Never use that: use a new version of Leo and use its @clean format, which doesn't use sentinels. Not only are sentinels offensive to look at in the managed file, this version of Leo occasionally gets confused and tries to use "//" for puppet comments instead of "#". (Yes, some of what puppet (and thus Leo) is managing is php.) But we're stuck with this version of Leo, because when newer versions of Leo read our Leo XML file, many of the nodes lose their content, namely, a catastrophic lack of backward compatibility. It would take me at least a month of getting nothing else done to re-ingest our puppet configuration into a newer Leo.
I stumbled upon an old comment* you made about dealing with orgmode and noweb when editing an erlang file (bit syntax). If you didn't find it yet, at the end of the file, insert:
Local Variables:
org-babel-noweb-wrap-start: "{{{"
org-babel-noweb-wrap-end: "}}}"
then you'll use {{{chunk-name}}} instead of <<chunk-name>>.There are many reposts that I'm also glad happen. They're often a reminder of something I've forgotten about and that I'm glad to see again, or sometimes they're just something I missed.
There are lots of chainsaws that look prettier than Husqvarna's and Stihl and yet those are the ones that most professionals will use.
Really, you are putting way too much effort into this argument. I learned how to program on 40x25 and consider what I have today an incredible luxury, if you want you can customize Leo to look better but to me it isn't worth the time, I would rather spend that time on my work.
Also, if you ever actually use a chainsaw, please do look at it as you are using it.
I would put glasses, ear defenders, gloves and boots higher on that safety gear list, when cutting firewood, doing minor pruning and lopping etc.. Wear a helmet when doing anything bigger, although wood is very dense and you shouldn't expect a helmet to save you if a decent size limb comes your way. Technique is everything - learn from an expert before trying it yourself.
Chain sharpening is a mystical, ancient art, all the experts I talk to have a different view on the right technique, ranging from bench grinders to intricate jigs to simple "file and feel". I've tried them all and it basically comes down to experience. Just as important is the even wear of the bar itself, once its worn more on one side than the other the cuts bend like bananas and you can only cut so deep before the saw gets no purchase on the wood at all.
I think chainsaws are as pretty as IDEs - which maybe isn't saying much, but I love 'em both anyway...
> Joseph Buford Cox invented what is now known as the chipper type chain for chain saws. He based his design on the C-shaped jaws of the larva of the timber beetle. > He only reached the fifth grade in his formal education.
from https://en.wikipedia.org/wiki/Joseph_Buford_Cox
If you think that sharpening is complicated now, think again, it must have been impossible before this guy.
I'm relatively new to it, but I did do a stress test once. Loaded several hundred (over a thousand?) files of source code. Apart from the initial conversion to nodes, it was fairly performant. Doing a cff on the whole code base was pretty fast.
I did have to disable the setting to poll for file changes, though. When you have so many files open, that will seriously slow things down. I believe this was over a network too (i.e. the files I was opening were on a remote machine).
On my old rusty system I usually experienced lags starting with some 10k nodes. Editor usually lags when content with longer lines (some hundred characters) or content with many lines (some hundred or thousand lines) is loaded. Directives in the content are influencing behaviour, as also the used syntax highlighting. Even activated features are influencing things of course. The declutter-code for example seems horrible ineficient and called way to often I think, but I haven't digged deeper there yet.
Though, it should be noted that in the last months some improvments were in progress, and the actual developer-version seems to behave a bit better on certain aspects. So version is also a factor.
My personal rule is to slim down leo-files when they go >10 MB.
This app is on most parts pure gargabe. Most things are just hacked together as pet features to satisfy urgent needs on the spot, and then forgotten as things "work". And those things have grown over the last 20 years, while the dev has no real clue about modern software development or UX, leading to the mess this software is today.
But if you reach the point where you accept defeat to this monster, and ignore all features, it can become quite useful.
I'd be interested to gain some insight into why you find Leo's UX pure garbage and how it should have grown over the years.
The key F1 opens the help-widget, which is an area with text, located besides the editor. This area is just there, has now controls, no way to move it or close it. There is some text in it that explains this area can be closed with some shortcut, except it does not work. I don't even know whether it's a problem with my setup, because leo,has no way to check this. Just broken by design. Notable is that this hacked-in area seems to be used by several other functionalitys and plugins. All with the same fails.
Another strange quirk of leo is the minibuffer. It's something people knowing emacs will understand, for the rest, it,s just a strange line at the bottom of the window not explaing what it does, what purpose it has or how they can use it. But ok, that's how it is, just following some fade of unrelated culture. Really interessing is the usage. You enter some text, then hit tab to invoke autocompletion and surprise..in another part of the application, unconnected to the textwidget of the minibuffer switches a tab and some new widget appears presenting a list of possible candidates. Not that Qt hasen't a way to present autocomplete-lists, but thats just how it is. Quirky hackish, ugly. And of only working as ling as the tablist is not hidden.
Another funny part is the menu. Just look up what is weitten in them, what name, what order they have, and how this compares to the established names and positions in pretty much every other application.
Or let's take the configuration. Nodes with some directives in the outline. No actual documentation or discoverability in the app itself. No support to prevent failures. Not even instant-loading of changed settings. Restart the program, good enough 20 years ago, good enough today.
Or let's take the API: Single letter variable names. Objects with hundreds of unrelated methods and no documentation. Plugins which are just python-modules imported from the python-path, and not real plugins with actual structure and API.
Oh, and the worst, plugins which just don't work and functions which have no obvious result because someone forgot to refresh the outline. Though, this is probably just one of the endless number of obvious bugs one encounters at some point.
I wonder if there has been any usability research on which model (single or two pane) is least obtrusive to flow of information to and from the user.
The "Screen Shots" link is broken.
It should be: https://www.leoeditor.com/screen-shots.html
But currently it points to nowhere.
I've tried Leo a couple of times and like the concept _a lot_, but never got on with the implementation.
High Sierra
Python 3 installed via Homebrew
pip3 install leo
Ran fine right out of the box.
> Leo is a PIM, IDE and outliner that accelerates the work flow of programmers, authors and web designers. Outline nodes may appear in more than one place, allowing multiple organizations of data within a single outline.
I still have no idea what this is after reading the front page other than being yet another IDE.
Leo is:
A fully-featured IDE, with many features inspired by Emacs.
An outliner. Everything in Leo is an outline.
A data manager, data manager and personal information manager.
A powerful scripting environment.
A tool for organizing and studying computer code.
Extensible via a simple plugin architecture.
A tool that plays well with IPython, Vim and Emacs.
Written in 100% pure Python
Leo’s unique features
Leo completely integrates Python scripting and outlines. Simulating the following features in Vim, Emacs or Eclipse is possible, just as it is possible to simulate Python in assembly language…
All commands and scripts have easy access to outline structure via a simple Python API.
For example, p.b is the body text of the selected outline node.
Scripts have full access to all of Leo’s sources.
Clones create multiple views of an outline.
Leo’s underlying data is a Directed Acyclic Graphs.
As a result, Leo organizes data in completely new ways.
Scripts and programs can be composed from outlines using outline-oriented directives.
Importers convert flat text into outlines.
@test and @suite scripts create unit tests automatically.
@button scripts apply scripts to outline data.And for those on small screens:
--
Leo is:
--
* A fully-featured IDE, with many features inspired by Emacs.
* An outliner. Everything in Leo is an outline.
* A data manager, data manager and personal information manager.
* A powerful scripting environment.
* A tool for organizing and studying computer code.
* Extensible via a simple plugin architecture.
* A tool that plays well with IPython, Vim and Emacs.
* Written in 100% pure Python
--
Leo’s unique features
--
Leo completely integrates Python scripting and outlines. Simulating the following features in Vim, Emacs or Eclipse is possible, just as it is possible to simulate Python in assembly language…
* All commands and scripts have easy access to outline structure via a simple Python API.
For example, p.b is the body text of the selected outline node.
Scripts have full access to all of Leo’s sources.
* Clones create multiple views of an outline.
Leo’s underlying data is a Directed Acyclic Graphs.
As a result, Leo organizes data in completely new ways.
* Scripts and programs can be composed from outlines using outline-oriented directives.
* Importers convert flat text into outlines.
* @test and @suite scripts create unit tests automatically.
* @button scripts apply scripts to outline data.
The current iteration seems to have added more features while basically being a outline editor -- imagine keeping code in Emacs's Org mode and being able to compile it.
I liked it, but it felt like it didn't have all the bells-and-whistles of modern IDEs and required a different way of dealing with code.
Something like this
https://github.com/nakkaya/ferret
The whole source code is in literate form in one org file.
https://news.ycombinator.com/item?id=14951116
and the literate source code is here ...
It wasn't originally written in literate style, but it was a very large codebase which almost nobody understood. Tim Daly put an enormous amount of effort into making it literate, so that anybody can be introduced to it.
Someone just has to come along and have a need for it.
Apparently one can use Leo like the Jupyter notebook, and indeed Leo can interface with Jupyter notebooks. I never tried that aspect of it, though.
Org mode already does that using Org Babel. I use it to take "code notes" (code blocks with their evaluated/compiled outputs with notes) for Python [0], Nim[0,1], Awk [2], PlantUML[3], etc.
[0]: https://scripter.co/notes/string-fns-nim-vs-python/
[1]: https://scripter.co/notes/nim/
it is emacs' org mode on steroids. If you don't like org mode, move along.
...And some of the side effects of the steroids are already showing (e.g. "you can embed html in markdown". Really? So it is now an html renderer with markdown 'shortcuts'?)
"Wow!"
Also, things like "Find all functions that contain some string and put them in a tree" is trivial, and used a lot.
These are out of the box. You can then script more advanced stuff in Python.
Even though it's all Python, it seems to handle heavy loads well. I once opened all the source code of my project at work (0.5M lines of code). It took a long time to load them the first time (initial conversion into nodes). But once I had them loaded, I could save it as a project and reopen easily. Then searching the whole code base for a string was pretty fast as well. I don't know how well Emacs can handle thousands of files...
The literate capability is really trivial as well. If you're coding with Leo, you likely will start using basic literate constructs. It's just natural.
But don't read too much into the comparison with org mode. I use org mode and Leo for very different things.
Wouldn't narrowed views in org-mode accomplish the same?
No. Narrowed views only let you see a subtree. This is about gathering nodes from different parts of the tree and putting views into them under another node.
Let me give some detailed examples - starting from some basics.
In Leo, if I open a .cpp file, it will make a node out of each function. If I edit any node and hit "Save", it will update the cpp file with the change. In Org mode, you can copy/paste code from an existing .cpp file into an org document, but the two are now distinct. A change in the org file doesn't affect the .cpp file. The best you can do is use tangle/weave - but that would involve a fair amount of work to convert your whole project/file. And probably won't play as well with the rest of your coworkers as Leo will.
A trivial example: I've cleaned up many of our .cpp files where we had multiple classes in one file, and the methods were all over the place. Since each method was a node, it was easy for me to group together all methods of each class so they are not scattered around the file. It was absolutely trivial.
Now to the bug example. You have a bug you need to explore. You have a Leo project that has all your source code. At the top level, you'll have a node called "Code". Under that, each file will be another node. Under each "file" node you'll have a node for each function. Back at the top level, you have another node called "Tests" - also hierarchically structured by type of test.
So now you create another top level node and call it "Bug". You can put in notes (e.g. Bugzilla ID, or copy/paste relevant portion from the bug text here). So now what you do is find all parts of the code that you think are involved in the bug. Make a "clone" of their nodes, and put them under your Bug node. So now those functions appear in two places - under the "Code" node, and under your "Bug" node. A clone is basically a "view". If you edit the text of a cloned node, all of its clones get updated. So you can now happily edit code under the Bug node, knowing that your files are getting updated. You can also clone relevant tests and again put them under the Bug node, and fix your tests. When you're done fixing the bug, just delete the "Bug" node.
A simpler example: My work involves some rather large classes that are essentially singletons (i.e. a hack to use global variables without calling them that). This causes headaches. So sometimes I need to know all the possible places in my code base where one of its members is updated. In Leo, with one command, I can tell it to search all the nodes for that string, make clones of them, and put them under a top level node. So now under that node I have all the places the variable is touched. Easy to quickly examine. This really sped up the rate at which I would understand unfamiliar parts of the code.
BTW, you can get deeper than the function level. I've often taking a long function and split it up into nodes. So some of my code explorations involve nodes that are parts of functions. It is quite easy to break up a function this way in Leo.
Anyway, it's not hard to add the missing outline-features that leo offers in a seperate mode. org-agenda and org-brain are already doing something like this. The question is just whether people really want it. Org-mode has a different philosophy from leo in terms of outlines..