config

Personal configuration.
git clone git://code.dwrz.net/config
Log | Files | Refs

go-tag.el (9150B)


      1 ;;; go-tag.el --- Edit Golang struct field tag -*- lexical-binding: t; -*-
      2 
      3 ;; Copyright (C) 2017 Brantou
      4 
      5 ;; Author: Brantou <brantou89@gmail.com>
      6 ;; URL: https://github.com/brantou/emacs-go-tag
      7 ;; Keywords: tools
      8 ;; Version: 1.1.0
      9 ;; Package-Requires: ((emacs "24.0")(go-mode "1.5.0"))
     10 
     11 ;; This program is free software: you can redistribute it and/or modify
     12 ;; it under the terms of the GNU General Public License as published by
     13 ;; the Free Software Foundation, either version 3 of the License, or
     14 ;; (at your option) any later version.
     15 
     16 ;; This program is distributed in the hope that it will be useful,
     17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
     18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     19 ;; GNU General Public License for more details.
     20 
     21 ;; You should have received a copy of the GNU General Public License
     22 ;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
     23 
     24 ;; This file is not part of GNU Emacs.
     25 
     26 ;;; Commentary:
     27 ;;
     28 ;; Edit field tags for golang struct fields, based on gomodifytags.
     29 ;; This package is inspired by GoAddTags of vim-go and go-add-tags.
     30 ;;
     31 
     32 ;;; Requirements:
     33 ;;
     34 ;; - gomodifytags :: https://github.com/fatih/gomodifytags
     35 ;;
     36 
     37 ;;; TODO
     38 ;;
     39 ;; - Provide better error feedback.
     40 ;; - Provide more configuration.
     41 ;;
     42 
     43 ;;; Code:
     44 
     45 (require 'go-mode)
     46 
     47 (defgroup go-tag nil
     48   "Modify field tag for struct fields."
     49   :prefix "go-tag-"
     50   :link '(url-link :tag "MELPA" "https://melpa.org/#/go-tag")
     51   :link '(url-link :tag "MELPA Stable" "https://stable.melpa.org/#/go-tag")
     52   :link '(url-link :tag "GitHub" "https://github.com/brantou/emacs-go-tag")
     53   :group 'go)
     54 
     55 (defcustom go-tag-command "gomodifytags"
     56   "The 'gomodifytags' command.
     57 from https://github.com/fatih/gomodifytags."
     58   :type 'string
     59   :group 'go-tag)
     60 
     61 (defcustom go-tag-args nil
     62   "Additional arguments to pass to go-tag."
     63   :type '(repeat string)
     64   :group 'go-tag)
     65 
     66 (defcustom go-tag-show-errors 'buffer
     67   "Where to display go-tag error output.
     68 It can either be displayed in its own buffer, in the echo area, or not at all."
     69   :type '(choice
     70           (const :tag "Own buffer" buffer)
     71           (const :tag "Echo area" echo)
     72           (const :tag "None" nil))
     73   :group 'go-tag)
     74 
     75 (defun go-tag--parse-tag (tags)
     76   (mapconcat
     77    'car
     78    (mapcar
     79     (lambda(str)
     80       (split-string str ","))
     81     (split-string tags))
     82    ","))
     83 
     84 (defun go-tag--parse-option (tags)
     85   (mapconcat 'identity
     86              (delete
     87               ""
     88               (split-string
     89                (mapconcat
     90                 (lambda(str-lst)
     91                   (when (< 1 (length str-lst))
     92                     (concat (car str-lst) "=" (cadr str-lst))))
     93                 (mapcar
     94                  (lambda(str)
     95                    (split-string str ","))
     96                  (split-string tags))
     97                 ",")
     98                ","))
     99              ","))
    100 
    101 ;;;###autoload
    102 (defun go-tag-open-github()
    103   "go-tag open Github page."
    104   (interactive)
    105   (browse-url "https://github.com/brantou/emacs-go-tag"))
    106 
    107 ;;;###autoload
    108 (defun go-tag-refresh (tags)
    109   "Refresh field TAGS for struct fields."
    110   (interactive "sTags: ")
    111   (let ((stags (go-tag--parse-tag tags))
    112         (options (go-tag--parse-option tags)))
    113     (when (string-equal stags "") (setq stags "json"))
    114     (if (use-region-p)
    115         (progn
    116           (go-tag--region-remove (region-beginning) (region-end) stags "")
    117           (go-tag--region (region-beginning) (region-end) stags options))
    118       (progn
    119         (go-tag--point-remove (position-bytes (point))  stags "")
    120         (go-tag--point (position-bytes (point))  stags options)))))
    121 
    122 ;;;###autoload
    123 (defun go-tag-add (tags)
    124   "Add field TAGS for struct fields."
    125   (interactive "sTags: ")
    126   (let ((stags (go-tag--parse-tag tags))
    127         (options (go-tag--parse-option tags)))
    128     (if (use-region-p)
    129         (go-tag--region (region-beginning) (region-end) stags options)
    130       (go-tag--point (position-bytes (point))  stags options))))
    131 
    132 (defun go-tag--region (start end tags &optional options)
    133   "Add field TAGS for the region between START and END."
    134   (let ((cmd-args (append
    135                    go-tag-args
    136                    (list "-line" (format "%S,%S" (line-number-at-pos start) (line-number-at-pos end))))))
    137     (go-tag--add cmd-args tags options)))
    138 
    139 (defun go-tag--point (point tags &optional options)
    140   "Add field TAGS for the struct under the POINT."
    141   (let ((cmd-args (append go-tag-args
    142                           (list "-offset" (format "%S" point)))))
    143     (go-tag--add cmd-args tags options)))
    144 
    145 (defun go-tag--add (cmd-args tags &optional options)
    146   "Init CMD-ARGS, add TAGS and OPTIONS to CMD-ARGS."
    147   (let ((tags (if (string-equal tags "") "json" tags)))
    148     (setq cmd-args
    149           (append cmd-args
    150                   (list "-add-tags" tags)))
    151     (unless (string-equal options "")
    152       (setq cmd-args
    153             (append cmd-args
    154                     (list "-add-options" options))))
    155     (go-tag--proc cmd-args)))
    156 
    157 ;;;###autoload
    158 (defun go-tag-remove (tags)
    159   "Remove field TAGS for struct fields."
    160   (interactive "sTags: ")
    161   (let ((stags (go-tag--parse-tag tags))
    162         (options (go-tag--parse-option tags)))
    163     (if (use-region-p)
    164         (go-tag--region-remove (region-beginning) (region-end) stags options)
    165       (go-tag--point-remove (position-bytes (point))  stags options))))
    166 
    167 (defun go-tag--region-remove (start end tags &optional options)
    168   "Remove field TAGS for the region between START and END."
    169   (let ((cmd-args (append
    170                    go-tag-args
    171                    (list "-line" (format "%S,%S" (line-number-at-pos start) (line-number-at-pos end))))))
    172     (go-tag--remove cmd-args tags options)))
    173 
    174 (defun go-tag--point-remove (point tags &optional options)
    175   "Add field TAGS for the struct under the POINT."
    176   (let ((cmd-args (append
    177                    go-tag-args
    178                    (list "-offset" (format "%S" point)))))
    179     (go-tag--remove cmd-args tags options)))
    180 
    181 (defun go-tag--remove(cmd-args tags &optional options)
    182   "Init CMD-ARGS, add TAGS and OPTIONS to CMD-ARGS."
    183   (progn
    184     (if (string-equal tags "")
    185         (setq cmd-args
    186               (append cmd-args
    187                       (list "-clear-tags")))
    188       (if (string-equal options "")
    189           (setq cmd-args
    190                 (append cmd-args
    191                         (list "-remove-tags" tags)))
    192         (let ((tags (go-tag--filter-tags tags options)))
    193           (unless (string-equal tags "")
    194             (setq cmd-args
    195                   (append cmd-args
    196                           (list "-remove-tags" tags))))
    197           (setq cmd-args
    198                 (append cmd-args
    199                         (list "-remove-options" options))))))
    200     (go-tag--proc cmd-args)))
    201 
    202 (defun go-tag--filter-tags (tags options)
    203   (let ((tag-lst (split-string tags ","))
    204         (option-alst (mapcar
    205                       (lambda (opt)
    206                         (let ((opt-pair (split-string opt "=")))
    207                           (cons (car opt-pair) (cadr opt-pair))))
    208                       (split-string options ","))))
    209     (mapconcat
    210      'identity
    211      (delete "" (split-string
    212                  (mapconcat
    213                   (lambda (tag)
    214                     (unless (assoc tag option-alst) tag))
    215                   tag-lst
    216                   ",") ","))
    217      ",")))
    218 
    219 (defun go-tag--proc (cmd-args)
    220   "Modify field tags based on CMD-ARGS.
    221 
    222   The tool used can be set via ‘go-tag-command` (default: go-tag)
    223  and additional arguments can be set as a list via ‘go-tag-args`."
    224   (let ((tmpfile (make-temp-file "go-tag" nil ".go"))
    225         (patchbuf (get-buffer-create "*Go-Tag patch*"))
    226         (errbuf (if go-tag-show-errors
    227                     (get-buffer-create "*Go-Tag Errors*")))
    228         (coding-system-for-read 'utf-8)
    229         (coding-system-for-write 'utf-8))
    230 
    231     (unwind-protect
    232         (save-restriction
    233           (widen)
    234           (if errbuf
    235               (with-current-buffer errbuf
    236                 (setq buffer-read-only nil)
    237                 (erase-buffer)))
    238           (with-current-buffer patchbuf
    239             (erase-buffer))
    240 
    241           (write-region nil nil tmpfile)
    242 
    243           (setq cmd-args (append cmd-args (list "-file" tmpfile "-w")))
    244 
    245           (message "Calling go-tag: %s %s" go-tag-command cmd-args)
    246           (if (zerop (apply #'call-process go-tag-command nil errbuf nil cmd-args))
    247               (progn
    248                 (if (zerop (call-process-region (point-min) (point-max) "diff" nil patchbuf nil "-n" "-" tmpfile))
    249                     (message "Buffer is already go-tag")
    250                   (go--apply-rcs-patch patchbuf)
    251                   (message "Applied go-tag"))
    252                 (if errbuf (go-tag--kill-error-buffer errbuf)))
    253             (message "Could not apply go-tag")
    254             (if errbuf
    255                 (progn
    256                   (message (with-current-buffer errbuf (buffer-string)))
    257                   (go-tag--kill-error-buffer errbuf)))))
    258 
    259       (kill-buffer patchbuf)
    260       (delete-file tmpfile))))
    261 
    262 (defun go-tag--kill-error-buffer (errbuf)
    263   "Kill ERRBUF."
    264   (let ((win (get-buffer-window errbuf)))
    265     (if win
    266         (quit-window t win)
    267       (kill-buffer errbuf))))
    268 
    269 (provide 'go-tag)
    270 
    271 ;;; go-tag.el ends here