Add indent parser
This commit is contained in:
commit
49ae22e18a
52
README.md
52
README.md
@ -42,15 +42,18 @@ In a buffer run `M-x origami-mode`, and start experimenting with any
|
|||||||
of the supplied origami interactive functions. I recommend binding
|
of the supplied origami interactive functions. I recommend binding
|
||||||
these to keys of your choice in the `origami-mode-map`.
|
these to keys of your choice in the `origami-mode-map`.
|
||||||
|
|
||||||
This has been tested on Emacs 24.3 and 24.4.
|
There is also `global-origami-mode` if you just want to enable origami
|
||||||
|
everywhere. For any major-mode that doesn't have explicit support,
|
||||||
|
origami will use the indentation of the buffer to determine folds.
|
||||||
|
|
||||||
|
Origami has been tested on Emacs 24.3, 24.4 and 24.5.
|
||||||
|
|
||||||
# What can it do?
|
# What can it do?
|
||||||
|
|
||||||
Origami works by parsing the buffer to determine a fold structure.
|
Origami works by parsing the buffer to determine a fold structure.
|
||||||
(Currently there is only support for determining the fold structure
|
|
||||||
using a parser.)
|
|
||||||
|
|
||||||
The following commands are supplied to manipulate folds in the buffer:
|
The following commands are supplied to manipulate folds in the
|
||||||
|
buffer - those in bold are particularly useful:
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
@ -89,7 +92,7 @@ The following commands are supplied to manipulate folds in the buffer:
|
|||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>origami-recursively-toggle-node</td>
|
<td><strong>origami-recursively-toggle-node</strong></td>
|
||||||
<td>Acts like org-mode header collapsing. Cycle a fold between open, recursively open, closed.</td>
|
<td>Acts like org-mode header collapsing. Cycle a fold between open, recursively open, closed.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
@ -109,7 +112,7 @@ The following commands are supplied to manipulate folds in the buffer:
|
|||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>origami-show-only-node</td>
|
<td><strong>origami-show-only-node</strong></td>
|
||||||
<td>Close everything but the folds necessary to see the point. Very useful for concentrating on an area of code.</td>
|
<td>Close everything but the folds necessary to see the point. Very useful for concentrating on an area of code.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
@ -124,12 +127,12 @@ The following commands are supplied to manipulate folds in the buffer:
|
|||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>origami-undo</td>
|
<td><strong>origami-undo</strong></td>
|
||||||
<td>Undo the last folding operation.</td>
|
<td>Undo the last folding operation.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>origami-redo</td>
|
<td><strong>origami-redo</strong></td>
|
||||||
<td>Redo the last undone folding operation.</td>
|
<td>Redo the last undone folding operation.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
@ -141,31 +144,38 @@ The following commands are supplied to manipulate folds in the buffer:
|
|||||||
|
|
||||||
# Does it support my favourite major-mode?
|
# Does it support my favourite major-mode?
|
||||||
|
|
||||||
Probably not. Currently out of the box support is provided for:
|
To some degree, yes. Currently out of the box support is provided for:
|
||||||
|
|
||||||
* C
|
* C
|
||||||
* C++
|
* C++
|
||||||
* Clojure
|
* Clojure
|
||||||
|
* Go
|
||||||
* Java
|
* Java
|
||||||
* Javascript
|
* Javascript
|
||||||
* Perl
|
|
||||||
* elisp
|
|
||||||
* Go
|
|
||||||
* PHP
|
* PHP
|
||||||
|
* Perl
|
||||||
|
* Python
|
||||||
|
* elisp
|
||||||
|
|
||||||
|
Anything not in this list will be folded using indentation. This works
|
||||||
|
surprisingly well for most major-modes and is great for folding text.
|
||||||
|
|
||||||
It should be trivial to add support for any language that uses braces
|
It should be trivial to add support for any language that uses braces
|
||||||
to delimit blocks. Just add to `origami-parser-alist` something like:
|
to delimit blocks. Just add to `origami-parser-alist` something like:
|
||||||
`(mode-name . origami-c-style-parser)`. Adding support for another
|
`(mode-name . origami-c-style-parser)`. Adding support for another
|
||||||
lisp dialect should be almost as simple.
|
lisp dialect should be almost as simple. With a little bit of effort
|
||||||
|
it shouldn't be too hard to create a parser for anything with start
|
||||||
|
and end delimiters (similar to braces). See the
|
||||||
|
`origami-c-style-parser` function for how to define this.
|
||||||
|
|
||||||
I'm happy to work on parsers for other languages if enough interest is
|
I'm happy to work on parsers for other languages if interest is
|
||||||
expressed.
|
expressed. Cut an issue and I'll see what I can do.
|
||||||
|
|
||||||
It should be fairly easy to write a parser. An origami parser is a
|
You can write your own parser too. An origami parser is a function
|
||||||
function that takes a 'create function' and returns a function taking
|
that takes a 'create function' and returns a function taking the
|
||||||
the string to be parsed. The returned function should return a list of
|
string to be parsed. The returned function should return a list of
|
||||||
fold nodes. Fold nodes are created using the passed-in create
|
fold nodes. Fold nodes are created using the passed-in create
|
||||||
function. Best to use an example:
|
function. Here is an example that creates a single fold node:
|
||||||
|
|
||||||
(defun my-amazing-parser (create)
|
(defun my-amazing-parser (create)
|
||||||
(lambda (content)
|
(lambda (content)
|
||||||
@ -174,6 +184,10 @@ function. Best to use an example:
|
|||||||
offset ; this allows you to show some of the start of the folded text
|
offset ; this allows you to show some of the start of the folded text
|
||||||
child-nodes))))
|
child-nodes))))
|
||||||
|
|
||||||
|
While I work on writing better documentation for parsing, I suggest
|
||||||
|
starting by looking at the current parsers in origami-parsers.el to
|
||||||
|
see how they work.
|
||||||
|
|
||||||
# How is this different from [yafolding](https://github.com/zenozeng/yafolding.el)?
|
# How is this different from [yafolding](https://github.com/zenozeng/yafolding.el)?
|
||||||
|
|
||||||
I wasn't aware of yafolding before writing this. It looks like origami
|
I wasn't aware of yafolding before writing this. It looks like origami
|
||||||
|
@ -44,6 +44,7 @@
|
|||||||
(js3-mode . origami-c-style-parser)
|
(js3-mode . origami-c-style-parser)
|
||||||
(go-mode . origami-c-style-parser)
|
(go-mode . origami-c-style-parser)
|
||||||
(php-mode . origami-c-style-parser)
|
(php-mode . origami-c-style-parser)
|
||||||
|
(python-mode . origami-indent-parser)
|
||||||
(emacs-lisp-mode . origami-elisp-parser)
|
(emacs-lisp-mode . origami-elisp-parser)
|
||||||
(lisp-interaction-mode . origami-elisp-parser)
|
(lisp-interaction-mode . origami-elisp-parser)
|
||||||
(clojure-mode . origami-clj-parser))
|
(clojure-mode . origami-clj-parser))
|
||||||
@ -65,6 +66,74 @@ position in the CONTENT."
|
|||||||
acc))))
|
acc))))
|
||||||
(reverse acc))))
|
(reverse acc))))
|
||||||
|
|
||||||
|
(defun origami-indent-parser (create)
|
||||||
|
(cl-labels ((lines (string) (origami-get-positions string ".*?\r?\n"))
|
||||||
|
(annotate-levels (lines)
|
||||||
|
(-map (lambda (line)
|
||||||
|
;; TODO: support tabs
|
||||||
|
(let ((indent (length (car (s-match "^ *" (car line)))))
|
||||||
|
(beg (cdr line))
|
||||||
|
(end (+ (cdr line) (length (car line)) -1)))
|
||||||
|
(if (s-blank? (s-trim (car line)))
|
||||||
|
'newline ;sentinel representing line break
|
||||||
|
(vector indent beg end (- end beg)))))
|
||||||
|
lines))
|
||||||
|
(indent (line) (if (eq line 'newline) -1 (aref line 0)))
|
||||||
|
(beg (line) (aref line 1))
|
||||||
|
(end (line) (aref line 2))
|
||||||
|
(offset (line) (aref line 3))
|
||||||
|
(collapse-same-level (lines)
|
||||||
|
(->>
|
||||||
|
(cdr lines)
|
||||||
|
(-reduce-from (lambda (acc line)
|
||||||
|
(cond ((and (eq line 'newline) (eq (car acc) 'newline)) acc)
|
||||||
|
((= (indent line) (indent (car acc)))
|
||||||
|
(cons (vector (indent (car acc))
|
||||||
|
(beg (car acc))
|
||||||
|
(end line)
|
||||||
|
(offset (car acc)))
|
||||||
|
(cdr acc)))
|
||||||
|
(t (cons line acc))))
|
||||||
|
(list (car lines)))
|
||||||
|
(remove 'newline)
|
||||||
|
reverse))
|
||||||
|
(create-tree (levels)
|
||||||
|
(if (null levels)
|
||||||
|
levels
|
||||||
|
(let ((curr-indent (indent (car levels))))
|
||||||
|
(->> levels
|
||||||
|
(-partition-by (lambda (l) (= (indent l) curr-indent)))
|
||||||
|
(-partition-all 2)
|
||||||
|
(-mapcat (lambda (x)
|
||||||
|
;takes care of multiple identical levels, introduced when there are newlines
|
||||||
|
(-concat
|
||||||
|
(-map 'list (butlast (car x)))
|
||||||
|
(list (cons (-last-item (car x)) (create-tree (cadr x)))))))))))
|
||||||
|
(build-nodes (tree)
|
||||||
|
(if (null tree) (cons 0 nil)
|
||||||
|
;; complexity here is due to having to find the end of the children so that the
|
||||||
|
;; parent encompasses them
|
||||||
|
(-reduce-r-from (lambda (nodes acc)
|
||||||
|
(destructuring-bind (children-end . children) (build-nodes (cdr nodes))
|
||||||
|
(let ((this-end (max children-end (end (car nodes)))))
|
||||||
|
(cons (max this-end (car acc))
|
||||||
|
(cons (funcall create
|
||||||
|
(beg (car nodes))
|
||||||
|
this-end
|
||||||
|
(offset (car nodes))
|
||||||
|
children)
|
||||||
|
(cdr acc))))))
|
||||||
|
'(0 . nil)
|
||||||
|
tree))))
|
||||||
|
(lambda (content)
|
||||||
|
(-> content
|
||||||
|
lines
|
||||||
|
annotate-levels
|
||||||
|
collapse-same-level
|
||||||
|
create-tree
|
||||||
|
build-nodes
|
||||||
|
cdr))))
|
||||||
|
|
||||||
(defun origami-build-pair-tree (create open close positions)
|
(defun origami-build-pair-tree (create open close positions)
|
||||||
(cl-labels ((build (positions)
|
(cl-labels ((build (positions)
|
||||||
;; this is so horrible, but fast
|
;; this is so horrible, but fast
|
||||||
|
@ -380,8 +380,9 @@ was last built."
|
|||||||
-last-item
|
-last-item
|
||||||
origami-fold-data)
|
origami-fold-data)
|
||||||
(origami-create-overlay beg end offset buffer)))))))
|
(origami-create-overlay beg end offset buffer)))))))
|
||||||
(-when-let (parser-gen (cdr (assoc (buffer-local-value 'major-mode buffer)
|
(-when-let (parser-gen (or (cdr (assoc (buffer-local-value 'major-mode buffer)
|
||||||
origami-parser-alist)))
|
origami-parser-alist))
|
||||||
|
'origami-indent-parser))
|
||||||
(funcall parser-gen create))))
|
(funcall parser-gen create))))
|
||||||
|
|
||||||
(defun origami-get-fold-tree (buffer)
|
(defun origami-get-fold-tree (buffer)
|
||||||
|
Loading…
Reference in New Issue
Block a user