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
|
||||
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?
|
||||
|
||||
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>
|
||||
<tr>
|
||||
@ -89,7 +92,7 @@ The following commands are supplied to manipulate folds in the buffer:
|
||||
</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>
|
||||
</tr>
|
||||
|
||||
@ -109,7 +112,7 @@ The following commands are supplied to manipulate folds in the buffer:
|
||||
</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>
|
||||
</tr>
|
||||
|
||||
@ -124,12 +127,12 @@ The following commands are supplied to manipulate folds in the buffer:
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>origami-undo</td>
|
||||
<td><strong>origami-undo</strong></td>
|
||||
<td>Undo the last folding operation.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>origami-redo</td>
|
||||
<td><strong>origami-redo</strong></td>
|
||||
<td>Redo the last undone folding operation.</td>
|
||||
</tr>
|
||||
|
||||
@ -141,31 +144,38 @@ The following commands are supplied to manipulate folds in the buffer:
|
||||
|
||||
# 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++
|
||||
* Clojure
|
||||
* Go
|
||||
* Java
|
||||
* Javascript
|
||||
* Perl
|
||||
* elisp
|
||||
* Go
|
||||
* 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
|
||||
to delimit blocks. Just add to `origami-parser-alist` something like:
|
||||
`(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
|
||||
expressed.
|
||||
I'm happy to work on parsers for other languages if interest is
|
||||
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
|
||||
function that takes a 'create function' and returns a function taking
|
||||
the string to be parsed. The returned function should return a list of
|
||||
You can write your own parser too. An origami parser is a function
|
||||
that takes a 'create function' and returns a function taking the
|
||||
string to be parsed. The returned function should return a list of
|
||||
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)
|
||||
(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
|
||||
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)?
|
||||
|
||||
I wasn't aware of yafolding before writing this. It looks like origami
|
||||
|
@ -44,6 +44,7 @@
|
||||
(js3-mode . origami-c-style-parser)
|
||||
(go-mode . origami-c-style-parser)
|
||||
(php-mode . origami-c-style-parser)
|
||||
(python-mode . origami-indent-parser)
|
||||
(emacs-lisp-mode . origami-elisp-parser)
|
||||
(lisp-interaction-mode . origami-elisp-parser)
|
||||
(clojure-mode . origami-clj-parser))
|
||||
@ -65,6 +66,74 @@ position in the CONTENT."
|
||||
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)
|
||||
(cl-labels ((build (positions)
|
||||
;; this is so horrible, but fast
|
||||
|
@ -380,8 +380,9 @@ was last built."
|
||||
-last-item
|
||||
origami-fold-data)
|
||||
(origami-create-overlay beg end offset buffer)))))))
|
||||
(-when-let (parser-gen (cdr (assoc (buffer-local-value 'major-mode buffer)
|
||||
origami-parser-alist)))
|
||||
(-when-let (parser-gen (or (cdr (assoc (buffer-local-value 'major-mode buffer)
|
||||
origami-parser-alist))
|
||||
'origami-indent-parser))
|
||||
(funcall parser-gen create))))
|
||||
|
||||
(defun origami-get-fold-tree (buffer)
|
||||
|
Loading…
Reference in New Issue
Block a user