QBobWatson / poporg

Emacs programming tool for editing strings or comments in Org mode or any other text mode
GNU General Public License v3.0
91 stars 9 forks source link

+TITLE: poporg — Editing program comments or strings with Org mode or other text modes

+OPTIONS: H:2

** Introduction

poporg is a small Emacs Lisp project to help editing program strings and comments using Org mode (or any other major mode). This can be useful as it is often more convenient to edit large pieces of text, like Emacs Lisp or Python docstrings, in an org-mode buffer instead of in a comment or a string.

Emacs does not easily handle multiple major modes in a single buffer. So far many solutions have been implemented, with varying degrees of success, but none is perfect. The poporg approach avoids the problem by extracting the text from the comment or the string from a buffer using a major programming mode, into a separate buffer to be edited in a text mode, but containing only that comment or that string. Once the edit is completed, the modified comment or string gets re-integrated in the buffer containing the program, replacing the original contents.

The main utility of this package is its ability to handle prefixes automatically. For comments, it finds all contiguous nonempty comments on their own line, and strips the common prefix before inserting into the editing buffer (see =poporg-comment-skip-regexp=). For strings, it checks if there is consistent indentation for the whole string (the opening delimiter of the string can only have whitespace before it), and uses that as the common prefix. For regions, it just uses a naive common prefix. When placing the edited text back in context, it adds the common prefix again, potentially stripping any trailing whitespace (see =poporg-delete-trailing-whitespace=). It can even adjust the fill column in the editing buffer to account for indentation (see =poporg-adjust-fill-column=).

** Installation

To install poporg, move file =poporg.el= to a place where Emacs will find it. You might byte-compile the file if you want. There are also [[https://github.com/dimitri/el-get][El-Get]] and [[http://melpa.milkbox.net/][MELPA]] recipes.

To use poporg, you need to pick some unused keybinding and add a few lines to your =~/.emacs= file, such as:

+BEGIN_SRC emacs-lisp

(autoload 'poporg-dwim "poporg" nil t) (global-set-key (kbd "C-c \"") 'poporg-dwim)

+END_SRC

It is important that this be a global keybinding, or at least that the command =poporg-dwim= be available from both the programming and the text editing buffers.

** Usage

The command =poporg-dwim= searches for a nearby comment or string (see =poporg-find-string-or-comment=) and, upon finding one, it opens an empty buffer in a new window with its contents available for editing. If the region is active then =poporg-dwim= inserts the region into the buffer instead. The original text is grayed out and set read-only to prevent editing in two places at once. After editing, running =poporg-dwim= again from the editing buffer kills the editing buffer and inserts the edited text back into its original context.

Hopefully =poporg-dwim= will do what you expect in most situations. It uses the buffer's syntax table for parsing, so it should adapt well to most modes (including sextuple-quoted strings in Python). If you run =poporg-dwim= in the vicinity of a grayed-out region that you are editing in another buffer, it pops to that buffer. It has the following limitations:

  1. It does not understand empty strings.
  2. It cannot deal very well with comments with ending delimiters.

For example, in c-mode, comments start with =/= and end with =/=. This is a problem because poporg needs a common prefix for all lines. In order to make poporg understand these comments, write them on separate lines like this:

+BEGIN_SRC c

/*

In this situation poporg will ignore the first and last lines because they are empty except for comment delimiters, and detect the common prefix == or =_= for the middle lines, depending on whether the == character is matched by =poporg-comment-skip-regexp=.

You will probably want to customize =poporg-edit-hook=, since that is where the major mode of the edit buffer is set. The minor mode =poporg-mode= is activated in the edit buffer. It contains the following keybindings by default:

| Command | Keybinding | Description | |------------------------+------------+-----------------------------------| | poporg-edit-exit | =C-x C-s= | Save edit and kill poporg buffer | | poporg-update | =C-c C-c= | Save edit and keep poporg buffer | | poporg-update-and-save | =C-c C-s= | Save edit and keep poporg buffer; then save the original buffer | |------------------------+------------+-----------------------------------|

You can add additional keybindings to =poporg-mode-map=. To abort the edit simply kill the buffer.

** History

poporg was originally written and maintained by François Pinard, who had incorporated ideas into it from previous Emacs projects of his. Joe Rabinoff refactored the package to use the buffer's syntax table for parsing, and subsequently took over maintainership.

** Other tools

Major programming modes show comments and strings in full, and when these comments or strings are written using Org, with all parts of a link visible, it may be disruptive to those sensible to line width limits. The nice [[https://github.com/seanohalpin/org-link-minor-mode][org-link-minor-mode]] tool takes good care of this, by hiding the usually invisible parts of an Org link in other modes.

Org comes with many tools for spreading Org over other major modes, including the following minor modes which may be /added/ to other major modes:

Command
orgstruct-mode
orgstruct++-mode
orgtbl-mode

Org also has the following globally available commands:

| Command | Usual keybinding | |--------------------------+------------------| | org-store-link | =C-c l= | | org-insert-link-global | =C-c L= | | org open-at-point-global | =C-c O= | |--------------------------+------------------|

** Extractor for Python The =extradoc.py= tool in this poporg* project has the purpose of extracting and processing the Org contents of a set of Python sources. I used the =.py= suffix just in case there could be other =extradoc.LANG= tools for similarly handling sources in other languages. This =extradoc.py= tool presumes that all Org text is made up by concatenating the content of all sextuple-quoted strings (I mean triple double-quoted strings). Moreover, prefixed strings are not recognized.