Stata: Atom Setup for markstat
Support
Last updated: January 18, 2021
I’ve got a pretty good setup for literate programming with Markdown and Stata. I’m using markstat
to convert the Markdown file into HTML, and Atom with some third-party packages and other customization as my text editor.
This gives me the following:
- Good syntax highlighting for both Markdown and Stata code inside fenced code blocks.
- No mouse required.
cmd-enter
runs the current line from Atom in Stata. Inside a fenced code block,cmd-shift-enter
runs that entire block in Stata. This mimics the ergonomics of Jupyter notebooks and RMarkdown documents. - Good final output as a
.html
file. Example: source.stmd
and output.html
Here’s a demo of what this looks like in practice (you will probably want to view this full-screen or watch it on Vimeo):
Setup instructions
Getting this setup working is a bit involved, but doesn’t require anything too exotic:
- Install these packages:
language-markdown
,stata-exec
,language-stata
. - Install a theme that provides full highlighting for
language-markdown
. I use Atom Monokai. More details in the “Syntax-theme support” section on thelanguage-markdown
page. - Add
text.md
to the list of grammars to scan in the settings for thespell-check
package. Add to
config.cson
undercore
:customFileTypes: “text.md”: [ “stmd” ]
Add custom functions to
~/.atom/init.js
to be able to run an entire fenced code block at once:// For shortcut for adding in a fenced code block for Stata atom.commands.add( 'atom-text-editor', 'markstat:insert-fenced-code-block', function() { snippetBody = '```stata\n$1\n```' atom.packages.activePackages.snippets.mainModule.insert(snippetBody) } ) atom.commands.add( 'atom-text-editor', 'markstat:execute-fenced-code-block', function() { var editor = atom.workspace.getActiveTextEditor(); if(editor === undefined) { return; } var cursor = editor.getCursorBufferPosition(); var cursor_pos = [cursor.row, cursor.column]; var start = false; editor.backwardsScanInBufferRange(/^```(s|stata)$/g, [[0, 0], cursor_pos], function (e) { start = e.range; e.stop(); }); var end = false; editor.scanInBufferRange(/^```$/g, [cursor_pos, [editor.getLineCount(), 0]], function (e) { end = e.range; e.stop() }); if (start === false || end === false) { return; } var selection = [[start.end.row + 1, 0], [end.start.row, end.start.column]]; editor.setSelectedScreenRange(selection); var editorElement = atom.views.getView(atom.workspace.getActiveTextEditor()) atom.commands.dispatch(editorElement, 'stata-exec:run') editor.getCursors()[0].setBufferPosition(cursor); } ) // Just a bonus for being able to select any fenced code block atom.commands.add( 'atom-text-editor', 'markdown:select-fenced-code-block', function () { var editor = atom.workspace.getActiveTextEditor(); if (editor === undefined) { return; } var cursor = editor.getCursorBufferPosition(); var cursor_pos = [cursor.row, cursor.column]; var start = false; editor.backwardsScanInBufferRange(/^```[a-z]*$/g, [[0, 0], cursor_pos], function (e) { start = e.range; e.stop(); }); var end = false; editor.scanInBufferRange(/^```$/g, [cursor_pos, [editor.getLineCount(), 0]], function (e) { end = e.range; e.stop() }); if (start === false || end === false) { return; } var selection = [[start.end.row + 1, 0], [end.start.row, end.start.column]]; editor.setSelectedScreenRange(selection); } )
Add a custom keymap so
cmd-enter
runs the current line in Stata,cmd-shift-enter
runs the entire fenced code block, andctrl-alt-i
inserts a new fenced code block (same shortcut used by RStudio for code blocks in RMarkdown):'.platform-darwin [data-grammar="text md"]:not([mini])': 'cmd-enter': 'stata-exec:run' 'cmd-shift-enter': 'markstat:execute-fenced-code-block' 'ctrl-alt-i': 'markstat:insert-fenced-code-block'
Modify the
-markstat-
command in Stata per the following diff:--- markstat.ado.original +++ ~/Library/Application Support/Stata/ado/plus/m/markstat.ado @@ -351,6 +351,7 @@ return(isIndented(line)) } else { + if(startsWith(line, "```stata")) return(1) // ```s/ or ```m/ or ```r/ for no echo if(!startsWith(line, "```")) return(0) next = ustrtrim(usubstr(line, 4, .))
This will allow
-markstat-
to recognize code blocks fenced with the standard `stata
fence. By default-markstat-
only supportss
(rather thanstata
) for the language name “info string” for fenced code blocks.Note that you will need to use the
strict
option to get-markstat-
to recognize the fenced code blocks.