Semi-automatic docstring generation in Atom

I stared writing an atom command that tries to generate a docstring for a julia function somewhat automatically. The current implementation (below) simply copies the line where the curser is and inserts it into a julia string above. It works, but:

  • The editor history is cluttered, to undo the operation one has to ctrl-z several times.
  • TODO: Extract all function arguments and create an argument list in the docstring.
  • TODO: Clean the inserted line, e.g., remove function keyword

Has anyone else attempted something similar? In atom or as a julia function? This is my very first attempt at writng atom commands and I have zero experience with coffeescript, so my progress is kind of slow. I will update this thread if I make any improvements.

# In .atom/init.coffee
atom.commands.add 'atom-text-editor', 'custom:docstring', ->
  editor = atom.workspace.getActiveTextEditor()
  editor.selectLinesContainingCursors()
  text = editor.getSelectedText()
  editor.moveUp()
  editor.insertNewline()
  editor.insertText('"""\n')
  editor.insertText(text)
  editor.insertText('\n"""')
  editor.moveUp(2)
  editor.moveToBeginningOfLine()

To bind the command to a keyboard shortcut, open keymap and insert something like

# In .atom/keymap.cson
'atom-workspace atom-text-editor:not([mini])':
    'ctrl-alt-d': 'custom:docstring'

Example output of current implementation:

"""
function classify(crps, docid, verbose=true)

"""
function classify(crps, docid, verbose=true)
    print("\n"^10)
    println("Document:\n", replace(crps[docid].text[1:2000], r"\s+", " "))
1 Like

Ooh, I like this.
Do you want to move this to a PR (or even an issue) at the julia-client repo? I’d be happy to give pointers/help, and I think this should actually be included in Juno once it’s a bit more polished.

That would be great, I will soon board a unpleasantly long flight, so I’ll have some time to polish things up. I’ll return with a pr /issue within a couple of days.

1 Like

I managed to make some slight progress. Need to fix the regexes capturing ,;), even though I have tried to tell them not to, trim some white spaces and extract some functionality into functions (my limited coffeescript knowledge didn’t include how to build a function). The implementation below produces the result further below.

atom.commands.add 'atom-text-editor', 'custom:docstring', ->
  editor = atom.workspace.getActiveTextEditor()
  editor.selectLinesContainingCursors()
  text = editor.getSelectedText()
  editor.moveUp()
  text = text.replace /function /, ""
  kwarg_split = text.split ";" # kwargs come after a ;
  if kwarg_split.length == 1 # Didn't find kwargs
    # editor.insertText("if -- no kwargs")
    kwargs = ""
    args = text.match( / *([\w\s\:=]+?)[;,\)]/g  ) # Match the first paren (, then match everything that ends with either of , ; )
    if args == null # Found no args either
      arg_text = ""
    else
      arg_text = "\# Arguments\n"
      for arg in args
        arg_text = "#{arg_text}- `#{arg}` \n"
    kwarg_text = ""
  else
    # editor.insertText("else -- found kwargs")
    arg_text = kwarg_split[0]
    args = arg_text.match( / *([\w\s\:=]+?)[;,\)]/g  )
    if args == null # Found no args
      arg_text = ""
    else
      arg_text = "\# Arguments\n"
      for arg in args
        arg_text = "#{arg_text}- `#{arg}` \n"
    kwarg_text = kwarg_split[1]
    kwargs = kwarg_text.match( / *([\w\s\:=]+)[;,\)]/g  )
    kwarg_text = "\n\# Keyword Arguments\n"
    for arg in kwargs
      kwarg_text = "#{kwarg_text}- `#{arg}` \n"

  # editor.insertText(name)
  docstring = "\"\"\"\n    #{text}\n#{arg_text}#{kwarg_text}\n\"\"\""
  editor.insertText(docstring)
  editor.moveUp(2)
  editor.moveToBeginningOfLine()

Result

"""
    long(mandatory, optional=3, typerestricted::Int = 3; kwarg = 5)

# Arguments
- `mandatory,` 
- ` optional=3,` 

# Keyword Arguments
- ` kwarg = 5)` 

"""
function long(mandatory, optional=3, typerestricted::Int = 3; kwarg = 5)
end
"""
    short(a)

# Arguments
- `a)` 

"""
function short(a)
end
"""
    noargs()


"""
function noargs()
end
"""
    typeannotated()::Int


"""
function typeannotated()::Int
    1
end
"""
    wherefun(a::T) where T

# Arguments
- `a::T)` 

"""
function wherefun(a::T) where T
end

"""
    long1(mandatory, optional=3, typerestricted::Int = 3; kwarg = 5) = "Hej"

# Arguments
- `mandatory,` 
- ` optional=3,` 

# Keyword Arguments
- ` kwarg = 5)` 

"""
long1(mandatory, optional=3, typerestricted::Int = 3; kwarg = 5) = "Hej"
4 Likes