4

I often find myself doing things like installations or debugging where I would like to be able to work in shell mode but be able to insert annotations as I go. BBEdit has something like this but suffers badly from being not EMACS.

Ideally, such a mode would have some simple syntax for blocks of text that aren't sent to the shell subprocess at all. One possibility is something like Python's triple-quoted strings, inserted ahead if the current command. For example:

$ echo "Here is one command"
$ echo "Here is a second command"
$ _

This would be the vanilla shell session, cursor at the underscore. CTRL-P a few times, CTRL-O, and you open a line in the previous command text.

$ echo "Here is one command"
_
$ echo "Here is a second command"
$ 

Now enter text.

$ echo "Here is one command"
""" This is a longish comment I'm inserting into the text that
won't be seen as a command, and thus won't be sent to the bottom 
as a shell command.

The block ends at the matching triple-quote, like this:
"""
$ echo "Here is a second command"
$ 

I'm sure it's not an excessively difficult hack, but it seems like other people may have wanted this in the past, and I'd rather find an existing package than build my own.

  • 3
    You may be interested in howardism.org/Technical/Emacs/literate-devops.html . This is a more documentation-oriented approach than you're talking about (and more complex in general, if you're not already familiar with org and babel), but it's a leap you might be keen to take. – phils Sep 18 '17 at 3:01
  • 3
    On the other end of the scale, you could alias rem='cat >/dev/null' in your shell (which does run a shell command, but otherwise more or less matches your needs). C-d to exit from the cat command when you've finished typing your comment. – phils Sep 18 '17 at 3:32
  • Do you want only to append annotations to the session (in which case I'd go with cat >/dev/null as suggested by phils), or do you also want to go back and annotate old commands (in which case you can just edit the buffer)? – Gilles Sep 18 '17 at 11:47
  • @phils "more documentation oriented" approach sounds promising. this thing with editing the buffer is that RET is hot -- hit return and (depending on context) shell-mode either throws an error or tries to execute your text. – Charlie Martin Sep 18 '17 at 15:51
  • @Gilles part of the comment above is for you. – Charlie Martin Sep 18 '17 at 15:52
4

Use Literate DevOps Method

I recommend using the literate devops method via org-mode, that @phils suggested in the comments, because of the ease of use and adaptable workflow.

Example Workflow

  1. Create or open an org-mode file to store an manage your notes and annotations. e.g. C-x C-f ex1-annotations.org

  2. Add a new shell SRC code block using built-in easy templates, i.e. <s TAB, or using org-babel-demarcate-block, i.e. C-c C-v d.

    The contents of the new file should be similar to the example below:

    #+BEGIN_SRC shell :results output
    #+END_SRC
    

    Note: I added :results output to display anything printed to STDOUT. This header will add or update a #+RESULTS: section under the code block anytime the block is evaluated using C-c C-c. If you do not want the output in the annotations file then use :results silent output to display the output in the mini-buffer.

    Tip: Only elisp is enabled by default. You need to explicitly enable other languages, i.e. shell.

  3. Add a command to the shell code block and evaluate by pressing C-c C-c while the cursor is inside block or place the cursor on the #+BEGIN_SRC line. Answer yes ENTER to the prompt in the mini-buffer, i.e. Evaluate this shell code block on your system? (yes or no).

    The contents of the new file should be similar to the example below:

    #+BEGIN_SRC shell :results output
      echo "Here is one command"
    #+END_SRC
    
    #+RESULTS:
    : Here is one command
    
  4. Place the cursor on the #+END_SRC and press line C-c C-v d to demarcate the shell block.

    The contents of the new file should be similar to the example below:

    #+BEGIN_SRC shell :results output
      echo "Here is one command"
    #+END_SRC
    
    #+BEGIN_SRC shell :results output
    #+END_SRC
    
    #+RESULTS:
    : Here is one command
    
  5. Add a new command to the shell code block and evaluate by pressing C-c C-c while the cursor is inside block or place the cursor on the #+BEGIN_SRC line.

    The contents of the new file should be similar to the example below:

    #+BEGIN_SRC shell :results output
      echo "Here is one command"
    #+END_SRC
    
    #+BEGIN_SRC shell :results output
      echo "Here is a second command"
    #+END_SRC
    
    #+RESULTS:
    : Here is a second command
    
  6. Add your notes and annotations between #+END_SRC of the preceeding block and the #+BEGIN_SRC current block.

    The contents of the new file should be similar to the example below:

    #+BEGIN_SRC shell :results output
      echo "Here is one command"
    #+END_SRC
    
    This is a longish comment I'm inserting into the text that won't be seen as a command, and thus won't be sent to the bottom as a shell command.
    
    #+BEGIN_SRC shell :results output
      echo "Here is a second command"
    #+END_SRC
    
    #+RESULTS:
    : Here is a second command
    
  7. Repeat steps 4 through 6 until the notes and annotations are complete.

Use Other org-mode Features

  • Literate Programming

    • Add #+PROPERTY: header-args :tangle script-name.sh :shebang "#!/usr/bin/env bash" line to file then press C-c C-v t to create a new script-name.sh file which contains the shell code blocks.

      • The contents of the org-mode file should be similar to the example below:

        #+PROPERTY: header-args :tangle script-name.sh :shebang "#!/usr/bin/env bash"
        
        #+BEGIN_SRC shell :results output
          echo "Here is one command"
        #+END_SRC
        
        This is a longish comment I'm inserting into the text that won't be seen as a command, and thus won't be sent to the bottom as a shell command.
        
        #+BEGIN_SRC shell :results output
          echo "Here is a second command"
        #+END_SRC
        
        #+RESULTS:
        : Here is a second command
        
      • The contents of the script-name.sh file should be similar to the example below:

        #!/usr/bin/env bash
        echo "Here is one command"
        
        echo "Here is a second command"
        
    • Export documentation multiple formats from annotations file, e.g. text, html, pdf, etc…

      To create a README.txt file:

      1. Add #+EXPORT_FILE_NAME: README.txt line to annotations file

        #+PROPERTY: header-args :tangle script-name.sh :shebang "#!/usr/bin/env bash"
        #+EXPORT_FILE_NAME: README.txt
        
        #+BEGIN_SRC shell :results output
          echo "Here is one command"
        #+END_SRC
        
        This is a longish comment I'm inserting into the text that won't be seen as a command, and thus won't be sent to the bottom as a shell command.
        
        #+BEGIN_SRC shell :results output
          echo "Here is a second command"
        #+END_SRC
        
        #+RESULTS:
        : Here is a second command
        
    • Press C-c C-v t to create a new README.txt file which contains the shell code blocks.

      ,----
      | echo "Here is one command"
      `----
      
      This is a longish comment I'm inserting into the text that won't be seen
      as a command, and thus won't be sent to the bottom as a shell command.
      
      ,----
      | echo "Here is a second command"
      `----
      

This code was tested using:
emacs version: GNU Emacs 25.2.1 (x86_64-unknown-cygwin, GTK+ Version 3.22.10)
Org mode version: 9.1.2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.