6
6
; ; Maintainer: Doug Davis <ddavis@ddavis.io>
7
7
; ; URL: https://github.com/douglasdavis/numpydoc.el
8
8
; ; SPDX-License-Identifier: GPL-3.0-or-later
9
- ; ; Version: 0.1 .0
9
+ ; ; Version: 0.2 .0
10
10
; ; Package-Requires: ((emacs "25.1") (s "1.12.0") (dash "2.18.0"))
11
11
; ; Keywords: convenience
12
12
30
30
; ; NumPy docstring style guide can be found at
31
31
; ; https://numpydoc.readthedocs.io/en/latest/format.html
32
32
; ;
33
- ; ; Customizations include opting in or out of a minibuffer prompt for
34
- ; ; entering various components of the docstring (which can be toggled
35
- ; ; with `numpydoc-toggle-prompt' ), templates for when opting out of
36
- ; ; the prompt, the quoting style used, and whether or not to include
37
- ; ; an Examples block. See the `numpydoc' customization group.
38
-
33
+ ; ; There are three ways that one can be guided to insert descriptions
34
+ ; ; for the components:
35
+ ; ;
36
+ ; ; 1. Minibuffer prompt (the default).
37
+ ; ; 2. yasnippet expansion (requires `yasnippet' to be installed)
38
+ ; ; 3. Nothing (template text is inserted).
39
+ ; ;
40
+ ; ; Convenience functions are provided to interactively configure the
41
+ ; ; insertion style symbol:
42
+ ; ; - `numpydoc-use-prompt'
43
+ ; ; - `numpydoc-use-yasnippet'
44
+ ; ; - `numpydoc-use-templates'
45
+ ; ;
39
46
; ;; Code:
40
47
41
48
(require 'cl-lib )
45
52
(require 'dash )
46
53
(require 's )
47
54
55
+ ; ; forward declare some yasnippet code.
56
+ (defvar yas-indent-line )
57
+ (declare-function yas-expand-snippet " yasnippet" )
58
+
48
59
; ;; customization code.
49
60
50
61
(defgroup numpydoc nil
51
62
" NumPy docstrings."
52
63
:group 'convenience
53
64
:prefix " numpydoc-" )
54
65
55
- (defcustom numpydoc-prompt-for-input t
56
- " If t, use minibuffer prompt to enter some docstring components.
57
- An interactive convenience function, `numpydoc-toggle-prompt' , is
58
- provided to toggle this value via command execution."
66
+ (defcustom numpydoc-insertion-style 'prompt
67
+ " Which insertion guide to use when generating the docstring.
68
+ When set to 'prompt the minibuffer will be used to prompt for
69
+ docstring components. Setting to 'yas requires yasnippet to be
70
+ installed and `yas-expand-snippet' will be used to insert components.
71
+ When nil, template text will be inserted."
59
72
:group 'numpydoc
60
- :type 'boolean )
73
+ :type '(choice (const :tag " None" nil )
74
+ (const :tag " Prompt" prompt)
75
+ (const :tag " Yasnippet" yas)))
61
76
62
77
(defcustom numpydoc-quote-char ?\"
63
78
" Character for docstring quoting style (double or single quote)."
@@ -110,6 +125,15 @@ text, and below the Examples section."
110
125
type
111
126
defval)
112
127
128
+ (defconst numpydoc--yas-replace-pat " --NPDOCYAS--"
129
+ " Temporary text to be replaced for yasnippet usage." )
130
+
131
+ (defun numpydoc--prompt-p ()
132
+ (eq numpydoc-insertion-style 'prompt ))
133
+
134
+ (defun numpydoc--yas-p ()
135
+ (eq numpydoc-insertion-style 'yas ))
136
+
113
137
(defun numpydoc--arg-str-to-struct (argstr )
114
138
" Convert ARGSTR to an instance of `numpydoc--arg' .
115
139
The argument takes on one of four possible styles:
@@ -301,19 +325,23 @@ This function assumes the cursor to be in the function body."
301
325
302
326
(defun numpydoc--insert-short-and-long-desc (indent )
303
327
" Insert short description with INDENT level."
304
- (let ((ld nil ))
328
+ (let ((ld nil )
329
+ (tmps (cond ((numpydoc--yas-p) numpydoc--yas-replace-pat)
330
+ (t numpydoc-template-short)))
331
+ (tmpl (cond ((numpydoc--yas-p) numpydoc--yas-replace-pat)
332
+ (t numpydoc-template-long))))
305
333
(insert " \n " )
306
334
(numpydoc--insert indent
307
335
(concat (make-string 3 numpydoc-quote-char)
308
- (if numpydoc-prompt-for-input
336
+ (if ( numpydoc-- prompt-p)
309
337
(read-string
310
338
(format " Short description: " ))
311
- numpydoc-template-short )
339
+ tmps )
312
340
" \n\n " )
313
341
(make-string 3 numpydoc-quote-char))
314
342
(forward-line -1 )
315
343
(beginning-of-line )
316
- (if numpydoc-prompt-for-input
344
+ (if ( numpydoc-- prompt-p)
317
345
(progn
318
346
(setq ld (read-string (concat " Long description "
319
347
" (or press return to skip): " )
@@ -324,7 +352,7 @@ This function assumes the cursor to be in the function body."
324
352
(numpydoc--fill-last-insertion)
325
353
(insert " \n " )))
326
354
(insert " \n " )
327
- (numpydoc--insert indent numpydoc-template-long )
355
+ (numpydoc--insert indent tmpl )
328
356
(insert " \n " ))))
329
357
330
358
(defun numpydoc--insert-item (indent name &optional type )
@@ -336,21 +364,25 @@ This function assumes the cursor to be in the function body."
336
364
337
365
(defun numpydoc--insert-item-and-type (indent name type )
338
366
" Insert parameter with NAME and TYPE at level INDENT."
339
- (let ((tp type))
367
+ (let ((tp type)
368
+ (tmpt (cond ((numpydoc--yas-p) numpydoc--yas-replace-pat)
369
+ (t numpydoc-template-type-desc))))
340
370
(unless tp
341
- (setq tp (if numpydoc-prompt-for-input
371
+ (setq tp (if ( numpydoc-- prompt-p)
342
372
(read-string (format " Type of %s : "
343
373
name))
344
- numpydoc-template-type-desc )))
374
+ tmpt )))
345
375
(numpydoc--insert indent (format " %s : %s \n " name tp))))
346
376
347
377
(defun numpydoc--insert-item-desc (indent element )
348
378
" Insert ELEMENT parameter description at level INDENT."
349
- (let ((desc (concat (make-string 4 ?\s )
350
- (if numpydoc-prompt-for-input
379
+ (let* ((tmpd (cond ((numpydoc--yas-p) numpydoc--yas-replace-pat)
380
+ (t numpydoc-template-desc)))
381
+ (desc (concat (make-string 4 ?\s )
382
+ (if (numpydoc--prompt-p)
351
383
(read-string (format " Description for %s : "
352
384
element))
353
- numpydoc-template-desc ))))
385
+ tmpd ))))
354
386
(numpydoc--insert indent desc)
355
387
(numpydoc--fill-last-insertion)
356
388
(insert " \n " )))
@@ -371,20 +403,22 @@ This function assumes the cursor to be in the function body."
371
403
372
404
(defun numpydoc--insert-return (indent fnret )
373
405
" Insert FNRET (return) description (if exists) at INDENT level."
374
- (when (and fnret (not (string= fnret " None" )))
375
- (insert " \n " )
376
- (numpydoc--insert indent
377
- " Returns\n "
378
- " -------\n "
379
- fnret)
380
- (insert " \n " )
381
- (numpydoc--insert indent
382
- (concat (make-string 4 ?\s )
383
- (if numpydoc-prompt-for-input
384
- (read-string " Description for return: " )
385
- numpydoc-template-desc)))
386
- (numpydoc--fill-last-insertion)
387
- (insert " \n " )))
406
+ (let ((tmpr (cond ((numpydoc--yas-p) numpydoc--yas-replace-pat)
407
+ (t numpydoc-template-desc))))
408
+ (when (and fnret (not (string= fnret " None" )))
409
+ (insert " \n " )
410
+ (numpydoc--insert indent
411
+ " Returns\n "
412
+ " -------\n "
413
+ fnret)
414
+ (insert " \n " )
415
+ (numpydoc--insert indent
416
+ (concat (make-string 4 ?\s )
417
+ (if (numpydoc--prompt-p)
418
+ (read-string " Description for return: " )
419
+ tmpr)))
420
+ (numpydoc--fill-last-insertion)
421
+ (insert " \n " ))))
388
422
389
423
(defun numpydoc--insert-exceptions (indent fnexcepts )
390
424
" Insert FNEXCEPTS (exception) elements at INDENT level."
@@ -399,20 +433,52 @@ This function assumes the cursor to be in the function body."
399
433
400
434
(defun numpydoc--insert-examples (indent )
401
435
" Insert function examples block at INDENT level."
402
- (when numpydoc-insert-examples-block
403
- (insert " \n " )
404
- (numpydoc--insert indent
405
- " Examples\n "
406
- " --------\n "
407
- (concat numpydoc-template-desc " \n " ))))
436
+ (let ((tmpd (cond ((numpydoc--yas-p) numpydoc--yas-replace-pat)
437
+ (t numpydoc-template-desc))))
438
+ (when numpydoc-insert-examples-block
439
+ (insert " \n " )
440
+ (numpydoc--insert indent
441
+ " Examples\n "
442
+ " --------\n "
443
+ (concat tmpd " \n " )))))
444
+
445
+ (defun numpydoc--yasnippetfy ()
446
+ " Take the template and convert to yasnippet then execute."
447
+ ; ; replace the template
448
+ (save-excursion
449
+ (python-nav-beginning-of-defun )
450
+ (let ((i 1 )
451
+ (start (point )))
452
+ (goto-char start)
453
+ (while (re-search-forward numpydoc--yas-replace-pat nil t )
454
+ (replace-match (format " ${%s } " i))
455
+ (setq i (+ 1 i)))))
456
+ ; ; execute the yasnippet
457
+ (save-excursion
458
+ (let ((ds-start (progn
459
+ (python-nav-beginning-of-statement )
460
+ (forward-char 3 )
461
+ (point )))
462
+ (ds-end (progn
463
+ (python-nav-end-of-statement )
464
+ (forward-char -3 )
465
+ (point ))))
466
+ (goto-char ds-start)
467
+ (set-mark-command nil )
468
+ (goto-char ds-end)
469
+ (kill-region 1 1 t )
470
+ (yas-expand-snippet (current-kill 0 t )
471
+ nil nil '((yas-indent-line 'nothing ))))))
408
472
409
473
(defun numpydoc--insert-docstring (indent fndef )
410
474
" Insert FNDEF with indentation level INDENT."
411
475
(numpydoc--insert-short-and-long-desc indent)
412
476
(numpydoc--insert-parameters indent (numpydoc--def-args fndef))
413
477
(numpydoc--insert-return indent (numpydoc--def-rtype fndef))
414
478
(numpydoc--insert-exceptions indent (numpydoc--def-raises fndef))
415
- (numpydoc--insert-examples indent))
479
+ (numpydoc--insert-examples indent)
480
+ (when (numpydoc--yas-p)
481
+ (numpydoc--yasnippetfy)))
416
482
417
483
(defun numpydoc--delete-existing ()
418
484
" Delete existing docstring."
@@ -433,10 +499,22 @@ This function assumes the cursor to be in the function body."
433
499
; ;; public API
434
500
435
501
;;;### autoload
436
- (defun numpydoc-toggle-prompt ()
437
- " Toggle the value of `numpydoc-prompt-for-input' ."
502
+ (defun numpydoc-use-yasnippet ()
503
+ " Enable yasnippet insertion (see `numpydoc-insertion-style' )."
504
+ (interactive )
505
+ (setq numpydoc-insertion-style 'yas ))
506
+
507
+ ;;;### autoload
508
+ (defun numpydoc-use-prompt ()
509
+ " Enable minibuffer prompt insertion (see `numpydoc-insertion-style' )."
510
+ (interactive )
511
+ (setq numpydoc-insertion-style 'prompt ))
512
+
513
+ ;;;### autoload
514
+ (defun numpydoc-use-templates ()
515
+ " Enable template text insertion (see `numpydoc-insertion-style' )."
438
516
(interactive )
439
- (setq numpydoc-prompt-for-input ( not numpydoc-prompt-for-input) ))
517
+ (setq numpydoc-insertion-style nil ))
440
518
441
519
;;;### autoload
442
520
(defun numpydoc-generate ()
0 commit comments