Skip to content

Instantly share code, notes, and snippets.

@bhyde
Last active June 25, 2017 18:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bhyde/8945d9de40e5b9a9cdc4a9ee37a8daaf to your computer and use it in GitHub Desktop.
Save bhyde/8945d9de40e5b9a9cdc4a9ee37a8daaf to your computer and use it in GitHub Desktop.
outshine-lang.py reworked for quelpa

This is a minor rework of outshine-lang so I can load it in my init file.

I do that via use-package + quelpa

Quelpa is a kind of virtual package repo that fetchs from files, github, etc.

So in my init file I find:

(use-package outshine
  :ensure t
  :commands outshine-hook-function
  :init
  (progn
    (add-hook 'outline-minor-mode-hook 'outshine-hook-function)
    (add-hook 'python-mode-hook 'outline-minor-mode))
  :config
  (progn
    (use-package outshine-lang
      :quelpa (:fetcher url :url "https://gist.githubusercontent.com/bhyde/8945d9de40e5b9a9cdc4a9ee37a8daaf/raw/53f197e2ef6726bdc192b1ed8f71117ea9b65af1/outshine-lang.el"))))
;;; outshine-lang.el --- allow outshine mode to fold language elements -*- lexical-binding: t; -*-
;; Copyright (C) 2017 Ilya Shlyakhter
;; Author: Ilya Shlyakhter
;; Keywords: lisp
;; Version: 0.0.2
;; License is missing
;;; Commentary:
;; I made minor changes to the original <https://personal.broadinstitute.org/ilya/outshine-python.el> and put it here so I
;; could load it with use-package via quelpa.
;; This code extends Thorsten Jolitz's excellent outshine mode ( http://orgmode.org/worg/org-tutorials/org-outside-org.html
;; ) to allow folding of language elements: classes, functions, and other language constructs. Language elements are
;; matched by user-specified regexps (see customization `outshine-lang-headline-regexps'). The outline levels of all
;; language element headlines are made to be greater than the levels of any standard outshine headlines, so that language
;; elements are always subordinate to outshine headlines. The outline level of a language headline is taken to be a
;; large fixed constant (specified by customization `outshine-lang-max-standard-level') plus the amount of whitespace
;; preceding the language headline. Since most code is pretty-printed in a hierarchical way (and Python is required to be),
;; this heuristic usually works well enough.
;;;; Implementation notes
;; This code works by redefining, via advice, `outline-regexp' and `outline-level' in outshine buffers.
;; The original values of these buffer-local variables (computed by outshine) are saved.
;; Then, `outline-regexp' is defined to match either standard or language headlines, and to capture the whitespace before
;; language headlines in a subexpression. `outline-level' is defined to call the original `outline-level' implementation
;; from outshine for standard headlines, and for language headlines to use indentation level to determine outline level.
;; For promotion/demotion commands, `outline-regexp' and `outline-level' are restored to outshine's original values;
;; these commands then act only on standard headlines.
;;; Code:
(require 'outshine)
(require 'rx)
;;; Customizations
(defgroup outshine-lang nil
"Extension allowing outshine mode to fold language elements"
:prefix "outshine-lang-"
:group 'outshine)
(defcustom outshine-lang-max-standard-level 10
"Max level of standard (non-language-expression) outline"
:group 'outshine-lang
:type 'integer)
(defcustom outshine-lang-headline-regexps
`(("python" . ,(rx-to-string '(:
(or "def" "class"
"with" "for" "if"
"##" ; to let the user insert headlines manually
)
space (1+ not-newline) (any "\:,") (0+ space) eol)))
("emacs-lisp" . ,(rx-to-string '(: "(def" (or "un" "var" "const" "group" "custom" "advice")))))
"Alist of language-specific outline headlines for outshine mode.
The name of the language (key-string) should be the associated
major-mode name without the '-mode' suffix, eg python for python-mode'.
The value should be a regexp that matches language elements which should
be headlines. The regexp should NOT match the whitespace before the language
element.
"
:group 'outshine-lang
:type '(alist :key-type string
:value-type regexp))
;;; Variables for saving outline-regexp and outline-level computed by outshine
(defvar outshine-lang-orig-outline-regexp nil
"Original value of `outline-regexp', before adding language headlines")
(make-variable-buffer-local 'outshine-lang-orig-outline-regexp)
(defvar outshine-lang-orig-outline-level nil
"Original value of `outline-level', before adding language headlines")
(make-variable-buffer-local 'outshine-lang-orig-outline-level)
;;; Utility functions
(defun outshine-lang-get-language-name ()
"Return language name for major-mode of current buffer.
Adapted from `navi-get-language-name'."
(car
(split-string
(symbol-name major-mode)
"-mode" 'OMIT-NULLS)))
(defun outshine-lang-get-headline-regexp ()
"Return the language-element headline regexp for the current buffer's language,
or nil if headline regexps are not defined for that language."
(cdr (assoc (outshine-lang-get-language-name) outshine-lang-headline-regexps)))
;;; Advice that modifies outshine behavior
(defadvice outline-static-level-p (around outshine-lang-set-lang-headline-level (level) activate)
"Prevent promotion/demotion commands from touching language headlines"
(setq ad-return-value
(if (outshine-lang-get-headline-regexp)
(>= level outshine-lang-max-standard-level)
ad-do-it)))
(defadvice outline-change-level (around outshine-lang-change-level-revert-to-orig-outline-defs (delta) activate)
"Revert to original expression"
(let ((outline-regexp outline-regexp)
(outline-level outline-level))
(when (outshine-lang-get-headline-regexp)
(setq outline-regexp outshine-lang-orig-outline-regexp
outline-level outshine-lang-orig-outline-level))
ad-do-it))
(defun outshine-lang-activate ()
"Turn language elems (function defs, class defs etc) into cycleable outshine-org headlines"
(let ((lang-elem-headline-re (outshine-lang-get-headline-regexp)))
(when lang-elem-headline-re
(setq
outshine-lang-orig-outline-regexp outline-regexp
outshine-lang-orig-outline-level outline-level
outline-regexp
;; Define a regexp which matches either language headlines or standard headlines.
;; If a language headline is matched, (match-string 1) gives matched headline and
;; (match-string 2) gives the whitespace preceding it; we take the length of the whitespace
;; to be the outline level.
(rx-to-string
`(or
(group
(group (0+ space))
(regexp ,lang-elem-headline-re))
(group (regexp ,outshine-lang-orig-outline-regexp))))
outline-level
(lambda ()
(if (match-string 1)
(+ outshine-lang-max-standard-level (length (match-string 2)))
(funcall outshine-lang-orig-outline-level)))))))
(defadvice outshine-hook-function (after outshine-lang-do-activate nil activate)
(outshine-lang-activate))
(provide 'outshine-lang)
;;; outshine-lang.el ends here
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment