├── .gitignore ├── LICENSE ├── README.md ├── gif ├── hs-cycle-all.gif └── hs-cycle.gif └── hideshow-orgmode.el /.gitignore: -------------------------------------------------------------------------------- 1 | *.py -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 logangrado 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | hideshow-orgmode.el 2 | =================== 3 | 4 | Hideshow-orgmode.el provides an org-mode like interface to the 5 | hideshow minor mode. 6 | 7 | `Org-mode` provides an elegant means of interacting with outlines that one can toggle with `TAB` and `S-TAB`. `Hideshow-orgmode.el` attempts to replicate the outline behavior of `org-mode` by providing two functions: `hs-cycle` and `hs-cycle-all`. 8 | 9 | ![](https://github.com/logangrado/hideshow-orgmode/blob/master/gif/hs-cycle-all.gif) 10 | 11 | ## Download 12 | 13 | $ git clone git@github.com:logangrado/hideshow-orgmode.git 14 | 15 | ## Installation 16 | 17 | (add-to-list 'load-path "/path/to/hideshow-orgmode-directory") 18 | (require 'hideshow-orgmode) 19 | 20 | ## Hideshow Cycling 21 | 22 | This package is designed to allow for the cycling of hidden code blocks much like org-mode. Each time hs-cycle is executed, it un-hides one additional block. When all blocks are shown, executing hs-cycle again hides all code blocks. 23 | 24 | ## Functions 25 | 26 | This package provides two functions: 27 | 28 | 1. `hs-cycle` - Cycles the current block 29 | 30 | 2. `hs-cycle-all` - Cycles all blocks 31 | 32 | 3. `hs-fold-all` - Folds all blocks. 33 | This function differes from `hideshow`'s `hs-hide-all` in that it also folds child blocks. This function is complimentary to `hs-show-all`, which unfolds all blocks. 34 | 35 | ## Keymaps & Tips 36 | 37 | I set this as my global keymaps in my init file. You of course are free to bind whatever you want. 38 | 39 | (global-set-key (kbd "C-c c") 'hs-cycle) 40 | (global-set-key (kbd "C-c C") 'hs-cycle-all) 41 | (global-set-key (kdb "C-c h") 'hs-fold-all) 42 | (global-set-key (kdb "C-c s") 'hs-show-all) 43 | 44 | I also added the following line to my init file, which automatically folds all blocks when opening a document, much like org-mode: 45 | 46 | (add-hook 'hs-minor-mode-hook 'hs-fold-all) 47 | 48 | ## Languages 49 | 50 | I've only really tested this package in `python major mode`. However, since the package leverages `hideshow`'s definition of foldable blocks, it \*should\* work anywhere `hideshow minor mode` works. 51 | 52 | ## Notes 53 | 54 | This package tries to replicate the successive unfolding of code blocks like org mode. Unlike org-mode, which leverages TAB, this package relies on binding a separate key. [Hideshow-org.el](https://github.com/shanecelis/hideshow-org) attempts to replicate the smart TAB functionality of org-mode. It would not be difficult combine hideshow-orgmode.el and hideshow-org.el to achieve true org-mode like code folding. However, for code without opening/closing brackets (I'm looking at you, Python), when the TAB key is pressed, emacs will cycle through possible indentations. 55 | 56 | ## TODO 57 | - [x] Currently, `hs-cycle` does not work when the cursor is *within* a blockstart regexp (i.e. for `class ClassName(object)...`, it doesn't detect that it is in a block if the cursor is on `lass` of `class`, but anywhere else is fine). This appears to be related to `hs-find-block-beginning`. 58 | -------------------------------------------------------------------------------- /gif/hs-cycle-all.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logangrado/hideshow-orgmode/b0c2dd29728faa78a4589b596c14b15eafbefd85/gif/hs-cycle-all.gif -------------------------------------------------------------------------------- /gif/hs-cycle.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logangrado/hideshow-orgmode/b0c2dd29728faa78a4589b596c14b15eafbefd85/gif/hs-cycle.gif -------------------------------------------------------------------------------- /hideshow-orgmode.el: -------------------------------------------------------------------------------- 1 | ;;; hideshow-orgmode.el --- Provides an outline-style interface for hideshow= 2 | 3 | ;; Author: Logan Grado 4 | 5 | ;; This file is free software; you can redistribute it and/or modify 6 | ;; it under the terms of the GNU General Public License as published by 7 | ;; the Free Software Foundation; either version 2, or (at your option) 8 | ;; any later version. 9 | 10 | ;; This file is distributed in the hope that it will be useful, 11 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ;; GNU General Public License for more details. 14 | 15 | ;; You should have received a copy of the GNU General Public License 16 | ;; along with GNU Emacs; see the file COPYING. If not, write to 17 | ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18 | ;; Boston, MA 02111-1307, USA. 19 | 20 | (require 'hideshow) 21 | (setq hs-allow-nesting t) ;;If this isn't set, child blocks won't rember their folded state 22 | 23 | ;;Interactive Functions 24 | ;;================================================================================ 25 | (defun hs-cycle () 26 | "Progressively shows more blocks under current block, then hide all blocks" 27 | (interactive) 28 | (hs-life-goes-on 29 | (save-excursion 30 | (move-beginning-of-line 1) 31 | (when (hs-find-block-beginning) 32 | (let (minp maxp) 33 | (setq minp (point)) ;Set minp to beg+1 34 | (funcall hs-forward-sexp-func 1) ;Goes to end of current block 35 | (setq maxp (point)) ;Set maxp to end-1s 36 | (if (hs-contains-hidden minp maxp) 37 | (hs-discard-overlays minp maxp) 38 | (hs-hide-recursive minp maxp))))))) 39 | 40 | (defun hs-cycle-all() 41 | "Progressive show more blocks all are shown, then hide all blocks" 42 | (interactive) 43 | (hs-life-goes-on 44 | (save-excursion 45 | (if (hs-contains-hidden (point-min) (point-max)) 46 | (hs-discard-overlays (point-min) (point-max)) 47 | (hs-hide-recursive (point-min) (point-max)))))) 48 | 49 | (defun hs-fold-all() 50 | "Hides all blocks. Differs from 'hs-hide-all' in that it also folds all child blocks" 51 | (interactive) 52 | (hs-life-goes-on 53 | (hs-find-block-beginning) ;go to beginning of block 54 | (save-excursion 55 | (goto-char (point-min)) 56 | (hs-hide-recursive (point-min) (point-max))))) 57 | 58 | (defun hs-fold-block() 59 | "Hides current block recursively" 60 | (interactive) 61 | (hs-life-goes-on 62 | (save-excursion 63 | (move-beginning-of-line 1) 64 | (let ((minp nil) (maxp nil)) 65 | (when (hs-find-block-beginning) 66 | (setq minp (point)) 67 | (funcall hs-forward-sexp-func 1) 68 | (setq maxp (1- (point))) 69 | (goto-char minp) 70 | (hs-hide-recursive minp maxp)))))) 71 | 72 | ;;Support functions 73 | ;;================================================================================ 74 | (defun hs-contains-hidden (minp maxp) 75 | "Returns nil if there is no overlay between minp and maxp" 76 | (goto-char minp) 77 | (let ((contains_hidden nil)) 78 | (while (progn 79 | (forward-comment (buffer-size)) ;forward-comment moves forward across count complete comments 80 | (and(and (< (point) maxp) ;Ensure we're not past maxp 81 | (re-search-forward hs-block-start-regexp maxp t)) 82 | (not contains_hidden))) ;Searches forward for next blockstart 83 | (setq contains_hidden (hs-already-hidden-p))) 84 | contains_hidden)) 85 | 86 | (defun hs-hide-recursive (minp maxp) 87 | "Hide all blocks between minp,maxp recursively (deepest level up)" 88 | (hs-life-goes-on 89 | (save-excursion 90 | (goto-char minp) 91 | (save-excursion 92 | (let ((maxd 3));(hs-max-depth minp maxp))) 93 | (while (> maxd 0) 94 | (goto-char minp) 95 | (hs-hide-level-recursive maxd minp maxp) 96 | (setq maxd (1- maxd))))) 97 | (hs-hide-block)))) 98 | 99 | ;; NOTE: I decided to remove this functionality. Recursively searching to find the 100 | ;; max depth was slow. Instead, I've adopted the 'org-mode' style of only folding 101 | ;; parents/children/leaves (only 3 levels), regardless of the actual max depth of the 102 | ;; region. 103 | 104 | ;; (defun hs-max-depth-recursive (depth minp maxp) 105 | ;; (when (hs-find-block-beginning) 106 | ;; (setq minp (1+ (point))) 107 | ;; (funcall hs-forward-sexp-func 1) 108 | ;; (setq maxp (1- (point)))) 109 | ;; (goto-char minp) 110 | 111 | ;; (let ((max_depth depth)) 112 | ;; (while (progn 113 | ;; (forward-comment (buffer-size)) 114 | ;; (and (< (point) maxp) 115 | ;; (re-search-forward hs-block-start-regexp maxp t))) 116 | ;; (if (and 117 | ;; (not (nth 3 (syntax-ppss))) ;t if NOT in string 118 | ;; (not (nth 4 (syntax-ppss)))) ;t if NOT in comment 119 | ;; (setq max_depth (max max_depth (hs-max-depth-recursive (1+ depth) (point) maxp))))) 120 | ;; max_depth)) 121 | 122 | ;; (defun hs-max-depth (&optional minp maxp) 123 | ;; (save-excursion 124 | ;; (if (not minp) (setq minp (point-min))) 125 | ;; (if (not maxp) (setq maxp (point-max))) 126 | ;; (goto-char minp) 127 | ;; (when (hs-find-block-beginning) 128 | ;; (setq minp (1+ (point))) 129 | ;; (funcall hs-forward-sexp-func 1) ;Goes to end of current block 130 | ;; (setq maxp (1- (point)))) ;Set maxp to end-1 131 | ;; (hs-max-depth-recursive 0 minp maxp))) 132 | 133 | ;;Provide 134 | (provide 'hideshow-orgmode) 135 | --------------------------------------------------------------------------------