#+TITLE:  General Programming Configuration
#+AUTHOR: Howard X. Abrams
#+DATE:   2020-10-26
#+FILETAGS: :emacs:

A literate programming file for helping me program.

#+BEGIN_SRC emacs-lisp :exports none
  ;;; general-programming --- Configuration for general languages. -*- lexical-binding: t; -*-
  ;;
  ;; © 2020-2022 Howard X. Abrams
  ;;   This work is licensed under a Creative Commons Attribution 4.0 International License.
  ;;   See http://creativecommons.org/licenses/by/4.0/
  ;;
  ;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
  ;; Maintainer: Howard X. Abrams
  ;; Created: October 26, 2020
  ;;
  ;; This file is not part of GNU Emacs.
  ;;
  ;; *NB:* Do not edit this file. Instead, edit the original literate file at:
  ;;            ~/other/hamacs/general-programming.org
  ;;       And tangle the file to recreate this one.
  ;;
  ;;; Code:
#+END_SRC

* Introduction

Seems that all programming interfaces and workflows behave similarly. However, one other helper routine is a =general= macro for org-mode files:
#+BEGIN_SRC emacs-lisp
  (general-create-definer ha-prog-leader
      :states '(normal visual motion)
      :keymaps 'prog-mode-map
      :prefix "SPC m"
      :global-prefix "<f17>"
      :non-normal-prefix "S-SPC")
#+END_SRC
* General
The following work for all programming languages.
** direnv
Farm off commands into /virtual environments/:
#+BEGIN_SRC emacs-lisp
  (use-package direnv
    :init
    (setq direnv--executable "/usr/local/bin/direnv"
          direnv-always-show-summary t
          direnv-show-paths-in-summary t)
    :config
    (direnv-mode))
#+END_SRC
** Spell Checking Comments
The [[https://www.emacswiki.org/emacs/FlySpell#h5o-2][flyspell-prog-mode]] only checks for misspellings in comments.

#+BEGIN_SRC emacs-lisp
(use-package flyspell
  :hook (prog-mode . flyspell-prog-mode))
#+END_SRC
** Flycheck
Why use [[https://www.flycheck.org/][flycheck]] over the built-in =flymake=? Speed used to be the advantage, however, I’m now pushing this stuff to LSP, so speed is less of an issue. However, what about when I am not using LSP? Also, since I’ve hooked up grammar stuff to it, I need this with global keybindings.

#+BEGIN_SRC emacs-lisp
  (use-package flycheck
    :bind (:map flycheck-error-list-mode-map
                ("C-n" . 'flycheck-error-list-next-error)
                ("C-p" . 'flycheck-error-list-previous-error)
                ("j"   . 'flycheck-error-list-next-error)
                ("k"   . 'flycheck-error-list-previous-error))
    :config
    (flymake-mode -1)
    (global-flycheck-mode)
    (ha-leader "t c" 'flycheck-mode)

    (ha-leader
      ">" '("next problem" . flycheck-next-error)
      "<" '("previous problem" . flycheck-previous-error)

      "P" '(:ignore t :which-key "problems")
      "P b" '("error buffer" . flycheck-buffer)
      "P c" '("clear" . flycheck-clear)
      "P n" '("next" . flycheck-next-error)
      "P p" '("previous" . flycheck-previous-error)
      "P l" '("list all" . flycheck-list-errors)
      "P y" '("copy errors" . flycheck-copy-errors-as-kill)
      "P s" '("select checker" . flycheck-select-checker)
      "P ?" '("describe checker" . flycheck-describe-checker)
      "P h" '("display error" . flycheck-display-error-at-point)
      "P e" '("explain error" . flycheck-explain-error-at-point)
      "P H" '("help" . display-local-help)
      "P i" '("manual" . flycheck-manual)
      "P V" '("version" . flycheck-version)
      "P v" '("verify-setup" . flycheck-verify-setup)
      "P x" '("disable-checker" . flycheck-disable-checker)
      "P t" '("toggle flycheck" . flycheck-mode)))
#+END_SRC
** Documentation
I’ve used the [[http://kapeli.com/][Dash]] API Documentation browser (an external application) with Emacs, however, this is only available for Mac.
#+BEGIN_SRC emacs-lisp :tangle no
  (use-package dash-at-point
    :commands (dash-at-point)
    :config
    (define-key evil-normal-state-map (kbd "g D") 'dash-at-point))
#+END_SRC
However, I’m interested in using [[https://devdocs.io/][devdocs]] instead, which is similar, but keeps it all /inside/ Emacs (and works on my Linux system). There are seems to be two competing Emacs projects for this.

The Emacs [[https://github.com/astoff/devdocs.el][devdocs]] project is active, and seems to work well. Its advantage is a special mode for moving around the documentation.

#+BEGIN_SRC emacs-lisp
  (use-package devdocs
    :after evil
    :config
    (define-key evil-normal-state-map (kbd "g D") 'devdocs-lookup)

    (ha-prog-leader
      "d"  '(:ignore t :which-key "docs")
      "d d" '("open" . devdocs-lookup)
      "d p" '("peruse" . devdocs-peruse)
      "d i" '("install" . devdocs-install)
      "d u" '("update" . devdocs-update-all)
      "d x" '("uninstall" . devdocs-delete)
      "d s" '("search" . devdocs-search)))
#+END_SRC

The [[https://github.com/blahgeek/emacs-devdocs-browser][devdocs-browser]] project acts similar, but with slightly different command names. Its advantage is that it allows for downloading docs and having it available offline, in fact, you can’t search for a function, until you download its pack. This is slightly faster because of this.

#+BEGIN_SRC emacs-lisp :tangle no
  (use-package devdocs-browser
    :config
    (define-key evil-normal-state-map (kbd "g D") 'devdocs-browser-open)

    (ha-prog-leader
      "d"  '(:ignore t :which-key "docs")
      "d d" '("open" . devdocs-browser-open)
      "d D" '("open in" . devdocs-browser-open-in)
      "d l" '("list" . devdocs-browser-list-docs)
      "d u" '("update" . devdocs-browser-update-docs)
      "d i" '("install" . devdocs-browser-install-doc)
      "d x" '("uninstall" . devdocs-browser-uninstall-doc)
      "d U" '("upgrade" . devdocs-browser-upgrade-doc)
      "d o" '("download" . devdocs-browser-download-offline-data)
      "d O" '("remove download" . devdocs-browser-remove-offline-data)))
#+END_SRC
** Language Server Protocol (LSP) Integration
The [[https://microsoft.github.io/language-server-protocol/][LSP]] is a way to connect /editors/ (like Emacs) to /languages/ (like Lisp)… wait, no, it was originally designed for VS Code and probably Python, but we now abstract away [[https://github.com/davidhalter/jedi][Jedi]] and the [[http://tkf.github.io/emacs-jedi/latest/][Emacs integration to Jedi]] (and duplicate everything for Ruby, and Clojure, and…).

Instead, we install [[https://emacs-lsp.github.io/lsp-mode/][LSP Mode]] (and friends), which simplifies my configuration:
#+BEGIN_SRC emacs-lisp
  (use-package lsp-mode
    :commands lsp
    :init
    ;; Let's make lsp-doctor happy with these settings:
    (setq gc-cons-threshold (* 100 1024 1024)
          read-process-output-max (* 1024 1024)
          company-idle-delay 0.0 ; Are thing fast enough to do this?
          lsp-keymap-prefix "s-m")
    :hook ((lsp-mode . lsp-enable-which-key-integration)))
#+END_SRC
I will want to start adding commands under my =SPC m= mode-specific key sequence leader, but in the meantime, all LSP-related keybindings are available under ~⌘-m~.  See [[https://emacs-lsp.github.io/lsp-mode/page/keybindings/][this page]] for the default keybindings.
*** UI
The [[https://github.com/emacs-lsp/lsp-ui][lsp-ui]] project offers much of the display and interface to LSP:

#+BEGIN_SRC emacs-lisp
  (use-package lsp-ui
    :commands lsp-ui-mode
    :config
    (setq lsp-ui-sideline-ignore-duplicate t
          lsp-ui-sideline-show-hover t
          lsp-ui-sideline-show-diagnostics t)
    :hook (lsp-mode . lsp-ui-mode))
#+END_SRC
*** Company Completion
The [[https://github.com/tigersoldier/company-lsp][company-lsp]] offers a [[http://company-mode.github.io/][company]] completion backend for [[https://github.com/emacs-lsp/lsp-mode][lsp-mode]]:

#+BEGIN_SRC emacs-lisp
  (use-package company-lsp
    :config
    (push 'company-lsp company-backends))
#+END_SRC
To options that might be interesting:
  - =company-lsp-async=: When set to non-nil, fetch completion candidates asynchronously.
  - =company-lsp-enable-snippet=: Set it to non-nil if you want to enable snippet expansion on completion. Set it to nil to disable this feature.

*** iMenu
The [[https://github.com/emacs-lsp/lsp-ui/blob/master/lsp-ui-imenu.el][lsp-imenu]] project offers a =lsp-ui-imenu= function for jumping to functions:

#+BEGIN_SRC emacs-lisp
  (use-package lsp-ui-imenu
      :straight nil
      :after lsp-ui
      :config
      (ha-prog-leader
        "g"  '(:ignore t :which-key "goto")
        "g m" '("imenu" . lsp-ui-imenu))
      (add-hook 'lsp-after-open-hook 'lsp-enable-imenu))
#+END_SRC
*** Treemacs
The [[https://github.com/emacs-lsp/lsp-treemacs][lsp-treemacs]] offers a project-specific structure oriented to the code:

#+BEGIN_SRC emacs-lisp
  (use-package lsp-treemacs
    :config
    (ha-prog-leader
          "0" '("treemacs" . lsp-treemacs-symbols)))
#+END_SRC
*** Origami Folding
The [[https://github.com/emacs-lsp/lsp-origami][lsp-origami]] project integrates the [[https://github.com/gregsexton/origami.el][origami]] project with LSP for /better code folding/:

#+BEGIN_SRC emacs-lisp
  (use-package lsp-origami
    :hook (lsp-after-open . lsp-origami-try-enable))
#+END_SRC
*** Debugging
Do we want to use a debugger?

#+BEGIN_SRC emacs-lisp :tangle no
  (use-package dap-mode
     :init
     (require 'dap-python))
#+END_SRC
** Function Call Notifications
As I've mentioned [[http://www.howardism.org/Technical/Emacs/beep-for-emacs.html][on my website]], I've created a [[file:~/website/Technical/Emacs/beep-for-emacs.org][beep function]] that notifies when long running processes complete.

#+BEGIN_SRC emacs-lisp
  (use-package alert
    :init
    (setq alert-default-style
          (if (ha-running-on-macos?)
              'osx-notifier
            'libnotify)))

  (use-package beep
    :straight nil   ; Already in the load-path
    :hook (after-init . (lambda () (beep--when-finished "Emacs has started")))
    :config
    (dolist (func '(org-publish
                    org-publish-all
                    org-publish-project
                    compile
                    shell-command))
      (advice-add func :around #'beep-when-runs-too-long)))
#+END_SRC
While that code /advices/ the publishing and compile commands, I may want to add more.
** iEdit
While there are language-specific ways to rename variables and functions, [[https://github.com/victorhge/iedit][iedit]] is often sufficient.

#+BEGIN_SRC emacs-lisp
  (use-package iedit
    :config
    (ha-leader "s e" '("iedit" . iedit-mode)))
#+END_SRC
** Commenting
I like =comment-dwim= (~M-;~), and I like =comment-box=, but I have an odd personal style that I like to codify:

#+BEGIN_SRC emacs-lisp
(defun ha-comment-line (&optional start end)
  (interactive "r")
  (when (or (null start) (not (region-active-p)))
    (setq start (line-beginning-position))
    (setq end   (line-end-position)))
  (save-excursion
    (narrow-to-region start end)
    (upcase-region start end)
    (goto-char (point-min))
    (insert "------------------------------------------------------------------------\n")
    (goto-char (point-max))
    (insert "\n------------------------------------------------------------------------")
    (comment-region (point-min) (point-max))
    (widen)))
#+END_SRC
And a keybinding:
#+BEGIN_SRC emacs-lisp
  (ha-prog-leader "c" '("comment line" . ha-comment-line))
#+END_SRC
** Evaluation
Typical keybindings for all programming modes:
#+BEGIN_SRC emacs-lisp
  (ha-prog-leader
     "e"  '(:ignore t :which-key "eval")
     "e ;" '("expression" . eval-expression)
     "e b" '("buffer" . eval-buffer)
     "e f" '("function" . eval-defun)
     "e r" '("region" . eval-region)
     "e e" '("last s-exp" . eval-last-sexp)
     "e p" '("print s-exp" . eval-print-last-sexp))
#+END_SRC
** Ligatures
The idea of using math symbols for a programming languages keywords is /cute/, but confusing when working with other people, and they are looking at my screen:

#+BEGIN_SRC emacs-lisp :tangle no
  (set-ligatures! 'python-mode nil)
#+END_SRC

The rest of the ligature system in Doom is nice.

** Task Runner
I've replaced my home-grown compilation list code with a more versatile [[https://github.com/emacs-taskrunner/emacs-taskrunner][Taskrunner project]].
#+BEGIN_SRC emacs-lisp :tangle no
(setq ivy-taskrunner-notifications-on t
      ivy-taskrunner-doit-bin-path "/usr/local/bin/doit")
#+END_SRC

Doom provides basic support, but we need more keybindings:

#+BEGIN_SRC emacs-lisp :tangle no
(map! :leader :prefix "p"
      :desc "Project tasks" "Z" 'ivy-taskrunner
      :desc "Reun last task" "z" 'ivy-taskrunner-rerun-last-command)
#+END_SRC

While my company is typically using =Rakefile= and =Makefile= in the top-level project, I want to have my personal tasks set per-project as well. For that, I thought about using [[https://pydoit.org/][doit]], where I would just create a =dodo.py= file that contains:

#+BEGIN_SRC python :tangle no
 def hello():
     """This command greets you."""
     return {
         'actions': [ 'echo hello' ],
     }
#+END_SRC

** Display Configuration
Using the [[https://github.com/seagle0128/doom-modeline][Doom Modeline]] to add notifications:
#+BEGIN_SRC emacs-lisp
(setq doom-modeline-lsp t)
(setq doom-modeline-env-version t)
#+END_SRC
* Languages
Simple to configure languages go here. More advanced stuff will go in their own files… eventually.
** YAML and Jinja
Doing a lot of [[https://github.com/yoshiki/yaml-mode][YAML work]], but this project needs a new maintainer.
#+BEGIN_SRC emacs-lisp
(use-package yaml-mode
  :mode "\\.ya?ml\\'")
#+END_SRC

Ansible uses Jinja, so we install the [[https://github.com/paradoxxxzero/jinja2-mode][jinja2-mode]]:
#+BEGIN_SRC emacs-lisp
(use-package jinja2-mode
  :mode (rx ".j2" eol))
#+END_SRC

** Emacs Lisp

Why yes, I do find I code a lot in Emacs…
#+BEGIN_SRC emacs-lisp
  (ha-auto-insert-file (rx ".el" eol) "emacs-lisp-mode.el")
#+END_SRC
However, most of my Emacs Lisp code is in literate org files.

*** Clever Parenthesis

The [[https://github.com/luxbock/evil-cleverparens][evil-cleverparens]] solves having me create keybindings to the [[https://github.com/Fuco1/smartparens][smartparens]] project by updating the evil states with Lisp-specific bindings.

#+BEGIN_SRC emacs-lisp
  (use-package evil-cleverparens
    :after smartparens-mode
    :custom
    evil-cleverparens-use-additional-bindings t
    evil-cleverparens-use-additional-movement-keys t
    evil-cleverparens-use-s-and-S nil ; using evil-sniper

    :init
    (require 'evil-cleverparens-text-objects)

    :hook (prog-mode . evil-cleverparens-mode))  ;; All the languages!
    ;; Otherwise: (emacs-lisp-mode . evil-cleverparens-mode)
#+END_SRC

I would like to have a list of what keybindings do what:
- ~M-h~ / ~M-l~ move back/forward by functions
- ~H~ / ~L~ move back/forward by s-expression
- ~M-i~ insert at the beginning of the form
- ~M-a~ appends at the end of the form
- ~M-o~ new form after the current sexp
- ~M-O~ new form /before/ the current sexp
- ~M-j~ / ~M-k~ drags /thing at point/ and back and forth in the form
- ~>~ slurp forward if at the end of form, at beginning, it barfs backwards
- ~<~ slurp backward if at start of form, at the end, it barfs forwards
- ~M-(~ / ~M-)~ wraps next/previous form in parens (braces and brackets work too)
- ~x~ unwraps if the point is on the =(= of an expression.
- ~D~ deletes an entire s-expression, but this can depend on the position of the point.

The other advantage is moving around by s-expressions. This takes a little getting used to, for instance:
- ~[~ and ~]~ move from paren to paren, essentially, from s-expression.
- ~H~ and ~L~ act similarly to the above.
- ~(~ and ~)~ move up to the parent s-expression

Other nifty keybindings that I need to commit to muscle memory include:

| ~M-q~ | =sp-indent-defun=   |
| ~M-J~ | =sp-join-sexp=      |
| ~M-s~ | =sp-splice-sexp=    |
| ~M-S~ | =sp-split-sexp=     |
| ~M-t~ | =sp-transpose-sexp= |
| ~M-v~ | =sp-convolute-sexp= |
| ~M-r~ | =sp-raise-sexp=     |

***** Eval Current Expression

A feature I enjoyed from Spacemacs is the ability to evaluate the s-expression currently containing the point. Not sure how how they made it, but cleverparens can help:

#+BEGIN_SRC emacs-lisp
(defun ha-eval-current-expression ()
  "Evaluates the expression the point is currently 'in'.
It does this, by jumping to the end of the current
expression (using evil-cleverparens), and evaluating what it
finds at that point."
  (interactive)
  (save-excursion
    (evil-cp-next-closing)
    (evil-cp-forward-sexp)
    (call-interactively 'eval-last-sexp)))
#+END_SRC

And we just need to bind it. The following is Doom-specific:

#+BEGIN_SRC emacs-lisp
  (ha-prog-leader
    "e c" '("current" . ha-eval-current-expression))
#+END_SRC
*** Dim those Parenthesis
The [[https://github.com/tarsius/paren-face][paren-face]] project lowers the color level of parenthesis which I find better.

#+BEGIN_SRC emacs-lisp
(use-package paren-face
  :hook (emacs-lisp-mode . paren-face-mode))
#+END_SRC
I'm going to play with the [[https://github.com/DogLooksGood/parinfer-mode][parinfer]] package.
*** Lispy
Sacha had an [[https://sachachua.com/blog/2021/04/emacs-making-a-hydra-cheatsheet-for-lispy/][interesting idea]] to /generate/ a Hydra from a mode map:

#+NAME: bindings
| key | function                      | column   |
|-----+-------------------------------+----------|
| <   | lispy-barf                    |          |
| A   | lispy-beginning-of-defun      |          |
| j   | lispy-down                    |          |
| Z   | lispy-edebug-stop             |          |
| B   | lispy-ediff-regions           |          |
| G   | lispy-goto-local              |          |
| h   | lispy-left                    |          |
| N   | lispy-narrow                  |          |
| y   | lispy-occur                   |          |
| o   | lispy-other-mode              |          |
| J   | lispy-outline-next            |          |
| K   | lispy-outline-prev            |          |
| P   | lispy-paste                   |          |
| l   | lispy-right                   |          |
| I   | lispy-shifttab                |          |
| >   | lispy-slurp                   |          |
| SPC | lispy-space                   |          |
| xB  | lispy-store-region-and-buffer |          |
| u   | lispy-undo                    |          |
| k   | lispy-up                      |          |
| v   | lispy-view                    |          |
| V   | lispy-visit                   |          |
| W   | lispy-widen                   |          |
| D   | pop-tag-mark                  |          |
| x   | see                           |          |
| L   | unbound                       |          |
| U   | unbound                       |          |
| X   | unbound                       |          |
| Y   | unbound                       |          |
| H   | lispy-ace-symbol-replace      | Edit     |
| c   | lispy-clone                   | Edit     |
| C   | lispy-convolute               | Edit     |
| n   | lispy-new-copy                | Edit     |
| O   | lispy-oneline                 | Edit     |
| r   | lispy-raise                   | Edit     |
| R   | lispy-raise-some              | Edit     |
| \   | lispy-splice                  | Edit     |
| S   | lispy-stringify               | Edit     |
| i   | lispy-tab                     | Edit     |
| xj  | lispy-debug-step-in           | Eval     |
| xe  | lispy-edebug                  | Eval     |
| xT  | lispy-ert                     | Eval     |
| e   | lispy-eval                    | Eval     |
| E   | lispy-eval-and-insert         | Eval     |
| xr  | lispy-eval-and-replace        | Eval     |
| p   | lispy-eval-other-window       | Eval     |
| q   | lispy-ace-paren               | Move     |
| z   | lispy-knight                  | Move     |
| s   | lispy-move-down               | Move     |
| w   | lispy-move-up                 | Move     |
| t   | lispy-teleport                | Move     |
| Q   | lispy-ace-char                | Nav      |
| -   | lispy-ace-subword             | Nav      |
| a   | lispy-ace-symbol              | Nav      |
| b   | lispy-back                    | Nav      |
| d   | lispy-different               | Nav      |
| f   | lispy-flow                    | Nav      |
| F   | lispy-follow                  | Nav      |
| g   | lispy-goto                    | Nav      |
| xb  | lispy-bind-variable           | Refactor |
| xf  | lispy-flatten                 | Refactor |
| xc  | lispy-to-cond                 | Refactor |
| xd  | lispy-to-defun                | Refactor |
| xi  | lispy-to-ifs                  | Refactor |
| xl  | lispy-to-lambda               | Refactor |
| xu  | lispy-unbind-variable         | Refactor |
| M   | lispy-multiline               | Other    |
| xh  | lispy-describe                | Other    |
| m   | lispy-mark-list               | Other    |


#+BEGIN_SRC emacs-lisp :var bindings=bindings :colnames yes :tangle no
(defvar my-lispy-bindings bindings)

(defvar ha-hydra-lispy-bindings
  (cl-loop for x in my-lispy-bindings
           unless (string= "" (elt x 2))
           collect
           (list (car x)
                 (intern (elt x 1))
                 (when (string-match "lispy-\\(?:eval-\\)?\\(.+\\)"
                                     (elt x 1))
                   (match-string 1 (elt x 1)))
                 :column
                 (elt x 2)))
  "Collection of memorable Lispy functions")

(eval
 `(defhydra
    ,(append '(("<f14>" nil :exit t)) ha-hydra-lispy-bindings )

   ))
(funcall defhydra
         `(my/lispy-cheat-sheet (:hint nil :foreign-keys run)
                                ))
(with-eval-after-load "lispy"
  (define-key lispy-mode-map (kbd "<f14>") 'my/lispy-cheat-sheet/body))
#+END_SRC

** Shell Scripts

While I don't like writing them, I can't get away from them.

While filename extensions work fine most of the time, I don't like to pre-pend =.sh= to the few shell scripts I write, and instead, would like to associate =shell-mode= with all files in a =bin= directory:

#+BEGIN_SRC emacs-lisp
  (use-package sh-mode
    :straight (:type built-in)
    :mode (rx (or (seq ".sh" eol)
                  "/bin/"))
    :config
    (ha-auto-insert-file (rx (or (seq ".sh" eol)
                  "/bin/")) "sh-mode.sh")
    :hook
    (after-save . executable-make-buffer-file-executable-if-script-p))
#+END_SRC
*Note:* we make the script /executable/ by default. See [[https://emacsredux.com/blog/2021/09/29/make-script-files-executable-automatically/][this essay]] for details, but it appears that the executable bit is only turned on if the script has a shebang at the top of the file.
** Fish Shell
#+BEGIN_SRC emacs-lisp
  (use-package fish-mode
    :mode (rx ".fish" eol)
    :config
    (ha-auto-insert-file (rx ".fish") "fish-mode.sh")
    :hook
    (fish-mode . (lambda () (add-hook 'before-save-hook 'fish_indent-before-save))))
#+END_SRC
* Technical Artifacts                                :noexport:
Provide a name in order to =require= this code.

#+BEGIN_SRC emacs-lisp :exports none
(provide 'ha-programming)
;;; ha-programming.el ends here
#+END_SRC

Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: ~C-c C-c~

#+DESCRIPTION: A literate programming file for helping me program.

#+PROPERTY:    header-args:sh :tangle no
#+PROPERTY:    header-args:emacs-lisp yes
#+PROPERTY:    header-args    :results none :eval no-export :comments no mkdirp yes

#+OPTIONS:     num:nil toc:nil todo:nil tasks:nil tags:nil date:nil
#+OPTIONS:     skip:nil author:nil email:nil creator:nil timestamp:nil
#+INFOJS_OPT:  view:nil toc:nil ltoc:t mouse:underline buttons:0 path:http://orgmode.org/org-info.js