# Semi-automatic docstring generation in Atom

**URL:** https://discourse.julialang.org/t/semi-automatic-docstring-generation-in-atom/14899
**Category:** Juno
**Tags:** documentation
**Created:** [September 13, 2018, 8:58am UTC](https://discourse.julialang.org/t/semi-automatic-docstring-generation-in-atom/14899 "2018-09-13T08:58:15Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)
#### Post date: [September 13, 2018, 8:58am UTC](https://discourse.julialang.org/t/semi-automatic-docstring-generation-in-atom/14899/1 "2018-09-13T08:58:15Z")

</div>

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.

```nohighlight
# 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

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

```

Example output of current implementation:

```julia
"""
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+", " "))

```

---

<div class="post-metadata">

### Author: ![pfitzseb](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pfitzseb/32/45566_2.png) [@pfitzseb](https://discourse.julialang.org/u/pfitzseb)
#### Post date: [September 13, 2018, 9:59am UTC](https://discourse.julialang.org/t/semi-automatic-docstring-generation-in-atom/14899/2 "2018-09-13T09:59:01Z")

</div>

Ooh, I like this.  
Do you want to move this to a PR (or even an issue) at [the julia-client](https://github.com/JunoLab/atom-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.

---

<div class="post-metadata">

### Author: ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)
#### Post date: [September 13, 2018, 10:05am UTC](https://discourse.julialang.org/t/semi-automatic-docstring-generation-in-atom/14899/3 "2018-09-13T10:05:52Z")

</div>

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.

---

<div class="post-metadata">

### Author: ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)
#### Post date: [September 14, 2018, 6:30am UTC](https://discourse.julialang.org/t/semi-automatic-docstring-generation-in-atom/14899/4 "2018-09-14T06:30:26Z")

</div>

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.

```nohighlight
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

```julia
"""
    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"

```
