emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[nongnu] elpa/go-mode 1db78fd 001/495: initial commit


From: ELPA Syncer
Subject: [nongnu] elpa/go-mode 1db78fd 001/495: initial commit
Date: Sat, 7 Aug 2021 09:04:31 -0400 (EDT)

branch: elpa/go-mode
commit 1db78fdc90023f0d6a9df23fb9fb2e1be7376a55
Author: Dominik Honnef <dominikh@fork-bomb.org>
Commit: Dominik Honnef <dominikh@fork-bomb.org>

    initial commit
---
 LEGAL      |  38 +++++
 LICENSE    |  20 +++
 go-mode.el | 505 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 563 insertions(+)

diff --git a/LEGAL b/LEGAL
new file mode 100644
index 0000000..849fe3f
--- /dev/null
+++ b/LEGAL
@@ -0,0 +1,38 @@
+Unless otherwise specified, all files and functions in this
+distribution are covered under the MIT license (see the file LICENSE.)
+
+The functions `gofmt`, `gofmt-replace-buffer`, `gofmt-apply-patch`,
+`gofmt-process-errors`, `gofmt-before-save`, `godoc-read-query`,
+`godoc-get-buffer`, `godoc-buffer-sentinel` and `godoc`, as defined in
+the file go-mode.el, are copyrighted free software by The Go Authors
+and licensed under the BSD license.
+
+    Copyright (c) 2012 The Go Authors. All rights reserved.
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+    * Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+    copyright notice, this list of conditions and the following
+    disclaimer in the documentation and/or other materials provided
+    with the distribution.
+
+    * Neither the name of Google Inc. nor the names of its
+    contributors may be used to endorse or promote products derived from
+    this software without specific prior written permission.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..2d99f93
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2013 Dominik Honnef
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/go-mode.el b/go-mode.el
new file mode 100644
index 0000000..4a404f5
--- /dev/null
+++ b/go-mode.el
@@ -0,0 +1,505 @@
+;;; go-mode.el --- Major mode for the Go programming language
+
+;; Improvements over original go-mode:
+;; - Use a proper syntax table, so that emacs and other packages know
+;;   about strings and comments (e.g. expand-region needs this)
+;; - Fix various indentation/font locking problems caused by the lack
+;;   of proper syntax table
+;; - Fix gofmt issue with buffers that do not end with a newline
+;; - Correctly fontify (foo)(bar) function calls
+;; - Correctly fontify identifiers with unicode characters in them
+;; - Fontifies type names in struct literals
+;; - Fontifies type names in maps, slices and arrays
+;; - Does not fontify anonymous functions as if they were methods
+;; - Support for C-M-a (beginning-of-defun)
+;; - Support for C-M-e (end-of-defun)
+;; - Support for C-M-h (mark-defun
+;; - go-goto-imports
+;;
+;; Minor changes:
+;; - use view-mode for the godoc buffer
+;;
+;; TODO:
+;; Features:
+;; - imports manipulations (add, remove, with sorting and grouping)
+;; Bugs:
+;; - Disable escapes in `` strings
+;; - Correct indentation for http://sprunge.us/iEaN
+;; - fontify types in struct definitions
+
+(defconst go-dangling-operators-regexp "[^-]-\\|[^+]\\+\\|[/*&><.=|^]")
+(defconst gofmt-stdin-tag "<standard input>")
+(defconst go-identifier-regexp "[[:word:][:multibyte:]_]+")
+(defconst go-func-regexp (concat "\\<func\\>\\s *\\(" go-identifier-regexp 
"\\)"))
+
+(defvar go-mode-syntax-table
+  (let ((st (make-syntax-table)))
+    (modify-syntax-entry ?+  "." st)
+    (modify-syntax-entry ?-  "." st)
+    (modify-syntax-entry ?%  "." st)
+    (modify-syntax-entry ?&  "." st)
+    (modify-syntax-entry ?|  "." st)
+    (modify-syntax-entry ?^  "." st)
+    (modify-syntax-entry ?!  "." st)
+    (modify-syntax-entry ?=  "." st)
+    (modify-syntax-entry ?<  "." st)
+    (modify-syntax-entry ?>  "." st)
+    (modify-syntax-entry ?/  ". 124b" st)
+    (modify-syntax-entry ?*  ". 23" st)
+    (modify-syntax-entry ?\n "> b" st)
+    (modify-syntax-entry ?\" "\"" st)
+    (modify-syntax-entry ?\' "\"" st)
+    (modify-syntax-entry ?`  "\"" st)
+    (modify-syntax-entry ?\\ "\\" st)
+    (modify-syntax-entry ?_  "_" st)
+
+    st)
+  "Syntax table for Go mode.")
+
+(defvar go-mode-keywords
+  '("break"    "default"     "func"   "interface" "select"
+    "case"     "defer"       "go"     "map"       "struct"
+    "chan"     "else"        "goto"   "package"   "switch"
+    "const"    "fallthrough" "if"     "range"     "type"
+    "continue" "for"         "import" "return"    "var")
+  "All keywords in the Go language.  Used for font locking and
+some syntax analysis.")
+
+
+(defvar go-mode-font-lock-keywords
+  (let ((builtins '("append" "cap" "close" "complex" "copy" "delete" "imag" 
"len"
+                    "make" "new" "panic" "print" "println" "real" "recover"))
+        (constants '("nil" "true" "false" "iota"))
+        (type-name "\\(?:[*(]\\)*\\(?:\\w+\\.\\)?\\(\\w+\\)") ;; XXX wtf? and 
what about unicode? and is this an identifier or wtf is it?
+        )
+    `((,(regexp-opt go-mode-keywords 'words) . font-lock-keyword-face)
+      (,(regexp-opt builtins 'words) . font-lock-builtin-face)
+      (,(regexp-opt constants 'words) . font-lock-constant-face)
+      (,go-func-regexp 1 font-lock-function-name-face) ;; function (not 
method) name
+      (,(concat "\\(" go-identifier-regexp "\\)\\s *(") 1 
font-lock-function-name-face) ;; function call/method name
+      (,(concat "(\\(" go-identifier-regexp "\\))\\s *(") 1 
font-lock-function-name-face) ;; bracketed function call
+      ("\\<type\\>\\s *\\(\\S +\\)" 1 font-lock-type-face) ;; types
+      (,(concat "\\<type\\>\\s *" go-identifier-regexp "\\s *" type-name) 1 
font-lock-type-face) ;; types
+      (,(concat 
"\\(?:[[:space:]]+\\|\\]\\)\\[\\([[:digit:]]+\\|\\.\\.\\.\\)?\\]" type-name) 2 
font-lock-type-face) ;; Arrays/slices
+      (,(concat "map\\[[^]]+\\]" type-name) 1 font-lock-type-face) ;; map 
value type
+
+      (,(concat "\\(" go-identifier-regexp "\\)" "{") 1 font-lock-type-face)
+
+      (,(concat "\\<map\\[" type-name) 1 font-lock-type-face) ;; map key type
+      (,(concat "\\<chan\\>\\s *\\(?:<-\\)?" type-name) 1 font-lock-type-face) 
;; channel type
+      (,(concat "\\<\\(?:new\\|make\\)\\>\\(?:\\s \\|)\\)*(" type-name) 1 
font-lock-type-face) ;; new/make type
+      ;; TODO do we actually need this one or isn't it just a function call?
+      (,(concat "\\.\\s *(" type-name) 1 font-lock-type-face) ;; Type 
conversion
+      (,(concat "\\<func\\>\\s +(" go-identifier-regexp "\\s +" type-name ")") 
1 font-lock-type-face) ;; Method receiver
+      ;; Like the original go-mode this also marks compound literal
+      ;; fields. There, it was marked as to fix, but I grew quite
+      ;; accustomed to it, so it'll stay for now.
+      ("^\\s *\\(\\w+\\)\\s *:\\(\\S.\\|$\\)" 1 font-lock-constant-face) ;; 
Labels and compound literal fields
+      ("\\<\\(goto\\|break\\|continue\\)\\>\\s *\\(\\w+\\)" 2 
font-lock-constant-face))) ;; labels in goto/break/continue
+  "Basic font lock keywords for Go mode.  Highlights keywords,
+built-ins, functions, and some types.")
+
+
+(defvar go-mode-map
+  (let ((m (make-sparse-keymap)))
+    (define-key m "}" 'go-mode-insert-and-indent)
+    (define-key m ")" 'go-mode-insert-and-indent)
+    (define-key m "," 'go-mode-insert-and-indent)
+    (define-key m ":" 'go-mode-insert-and-indent)
+    (define-key m "=" 'go-mode-insert-and-indent)
+    m)
+  "Keymap used by Go mode to implement electric keys.")
+
+(defun go-mode-insert-and-indent (key)
+  "Invoke the global binding of KEY, then reindent the line."
+
+  (interactive (list (this-command-keys)))
+  (call-interactively (lookup-key (current-global-map) key))
+  (indent-according-to-mode))
+
+(defun go-paren-level ()
+  (car (syntax-ppss)))
+
+(defun go-in-string-or-comment-p ()
+  (nth 8 (syntax-ppss)))
+
+(defun go-in-string-p ()
+  (nth 3 (syntax-ppss)))
+
+(defun go-in-comment-p ()
+  (nth 4 (syntax-ppss)))
+
+(defun go-goto-beginning-of-string-or-comment ()
+  (goto-char (nth 8 (syntax-ppss))))
+
+(defun go-backward-irrelevant ()
+  (let (pos (start-pos (point)))
+    (skip-chars-backward "\n[:blank:]")
+    (if (looking-back "`")
+        (backward-char))
+    (if (go-in-string-p)
+        (go-goto-beginning-of-string-or-comment))
+    (if (looking-back "\\*/")
+        (backward-char))
+    (if (go-in-comment-p)
+        (go-goto-beginning-of-string-or-comment))
+    (setq pos (point))
+    (beginning-of-line)
+    (if (or (looking-at "^[[:word:]]+:$") (looking-at "^[[:space:]]*\\(case 
.+\\|default\\):"))
+        (progn (previous-line)
+               (end-of-line))
+      (goto-char pos))
+    (if (not (= start-pos (point)))
+        (go-backward-irrelevant))
+    (not (= start-pos (point)))))
+
+(defun go-previous-line-has-dangling-op-p ()
+  (save-excursion
+    (beginning-of-line)
+    (go-backward-irrelevant)
+    (looking-back go-dangling-operators-regexp)))
+
+(defun go-indentation-at-point (point)
+  (save-excursion
+    (let (start-nesting line-begin (outindent 0))
+      (goto-char point)
+      (back-to-indentation)
+      (if (go-in-string-p)
+          (current-indentation)
+        (progn
+          (setq start-nesting (go-paren-level))
+          (if (looking-at "[])}]")
+              (progn
+                (while (and
+                        (not (bobp))
+                        (>= (go-paren-level) start-nesting))
+                  (skip-chars-backward "^[]{}()")
+                  (backward-char))
+                (if (go-previous-line-has-dangling-op-p)
+                    (- (current-indentation) tab-width)
+                  (current-indentation)))
+            (progn
+              (go-backward-irrelevant)
+              (if (looking-back go-dangling-operators-regexp)
+                  ;; only one nesting for all dangling operators in one 
operation
+                  (if (go-previous-line-has-dangling-op-p)
+                      (current-indentation)
+                    (+ (current-indentation) tab-width))
+                (progn
+                  (if (go-previous-line-has-dangling-op-p)
+                      (setq outindent tab-width))
+                  (setq line-begin (line-beginning-position))
+                  (while (and
+                          (not (bobp))
+                          (> (point) line-begin)
+                          (>= (go-paren-level) start-nesting))
+                    (if (= 0 (skip-chars-backward "^[]{}()" line-begin))
+                        (backward-char)))
+                  (if (and (< (go-paren-level) start-nesting))
+                      (+ (current-indentation) tab-width (- outindent))
+                    (- (current-indentation) outindent)))))))))))
+
+(defun go-mode-indent-line ()
+  (interactive)
+  (let ((indent (go-indentation-at-point (point)))
+        shift-amt
+        end
+        (pos (- (point-max) (point)))
+        (beg (progn (beginning-of-line) (point))))
+    (back-to-indentation)
+    (if (looking-at "case .+:[[:space:]]*$\\|default:[[:space:]]*$")
+        (setq indent (- indent tab-width)))
+    (beginning-of-line)
+    (if (and (looking-at "^[[:space:]]*[[:word:]]+:$")
+             (not (looking-at "^[[:space:]]*default:$")))
+        (setq indent 0))
+    (skip-chars-forward " \t")
+    (setq shift-amt (- indent (current-column)))
+    (if (zerop shift-amt)
+        nil
+      (delete-region beg (point))
+      (indent-to indent))
+    ;; If initial point was within line's indentation,
+    ;; position after the indentation.  Else stay at same point in text.
+    (if (> (- (point-max) pos) (point))
+        (goto-char (- (point-max) pos)))))
+
+(defun go-beginning-of-defun (&optional count)
+  (interactive "p")
+  (unless count (setq count 1))
+  (let ((first t) failure)
+    (dotimes (i (abs count))
+      (while (or first (go-in-string-or-comment-p))
+        (if (>= count 0)
+            (if (not (re-search-backward go-func-regexp nil t))
+                (setq failure t))
+          (if (looking-at go-func-regexp)
+              (forward-char))
+          (if (not (re-search-forward go-func-regexp nil t))
+              (setq failure t)))
+        (setq first nil)))
+    (if (< count 0)
+        (beginning-of-line))
+    (not failure)))
+
+(defun go-end-of-defun ()
+  (let (orig-level)
+    ;; It can happen that we're not placed before a function by emacs
+    (if (not (looking-at "func"))
+        (go-beginning-of-defun -1))
+    (skip-chars-forward "^{")
+    (forward-char)
+    (setq orig-level (go-paren-level))
+    (while (>= (go-paren-level) orig-level)
+      (skip-chars-forward "^}")
+      (forward-char))))
+
+;;;###autoload
+(define-derived-mode go-mode fundamental-mode "Go"
+  "Major mode for editing Go source text.
+
+This provides basic syntax highlighting for keywords, built-ins,
+functions, and some types.  It also provides indentation that is
+\(almost) identical to gofmt."
+
+  ;; Font lock
+  (set (make-local-variable 'font-lock-defaults)
+       '(go-mode-font-lock-keywords))
+
+  ;; Indentation
+  (set (make-local-variable 'indent-line-function) 'go-mode-indent-line)
+
+  ;; Comments
+  (set (make-local-variable 'comment-start) "// ")
+  (set (make-local-variable 'comment-end)   "")
+  (set (make-local-variable 'comment-use-syntax) t)
+  (set (make-local-variable 'comment-start-skip) "\\(//+\\|/\\*+\\)\\s *")
+
+  (set (make-local-variable 'beginning-of-defun-function) 
'go-beginning-of-defun)
+  (set (make-local-variable 'end-of-defun-function) 'go-end-of-defun)
+
+
+  (setq imenu-generic-expression
+        '(("type" "^type *\\([^ \t\n\r\f]*\\)" 1)
+          ("func" "^func *\\(.*\\) {" 1)))
+  (imenu-add-to-menubar "Index")
+
+  ;; Go style
+  (setq indent-tabs-mode t)
+
+  ;; Handle unit test failure output in compilation-mode
+  ;;
+  ;; Note the final t argument to add-to-list for append, ie put these at the
+  ;; *ends* of compilation-error-regexp-alist[-alist]. We want go-test to be
+  ;; handled first, otherwise other elements will match that don't work, and
+  ;; those alists are traversed in *reverse* order:
+  ;; http://lists.gnu.org/archive/html/bug-gnu-emacs/2001-12/msg00674.html
+  (when (and (boundp 'compilation-error-regexp-alist)
+             (boundp 'compilation-error-regexp-alist-alist))
+    (add-to-list 'compilation-error-regexp-alist 'go-test t)
+    (add-to-list 'compilation-error-regexp-alist-alist
+                 '(go-test . ("^\t+\\([^()\t\n]+\\):\\([0-9]+\\):? .*$" 1 2)) 
t)))
+
+;;;###autoload
+(add-to-list 'auto-mode-alist (cons "\\.go\\'" 'go-mode))
+
+;;;###autoload
+(defun gofmt ()
+  "Pipe the current buffer through the external tool `gofmt`.
+Replace the current buffer on success; display errors on failure."
+
+  (interactive)
+  (let ((currconf (current-window-configuration)))
+    (let ((srcbuf (current-buffer))
+          (filename buffer-file-name)
+          (patchbuf (get-buffer-create "*Gofmt patch*")))
+      (with-current-buffer patchbuf
+        (let ((errbuf (get-buffer-create "*Gofmt Errors*"))
+              (coding-system-for-read 'utf-8)    ;; use utf-8 with subprocesses
+              (coding-system-for-write 'utf-8))
+          (with-current-buffer errbuf
+            (toggle-read-only 0)
+            (erase-buffer))
+          (with-current-buffer srcbuf
+            (save-restriction
+              (let (deactivate-mark)
+                (widen)
+                ;; If this is a new file, diff-mode can't apply a
+                ;; patch to a non-exisiting file, so replace the buffer
+                ;; completely with the output of 'gofmt'.
+                ;; If the file exists, patch it to keep the 'undo' list happy.
+                (let* ((newfile (not (file-exists-p filename)))
+                       (flag (if newfile "" " -d")))
+
+                  ;; diff-mode doesn't work too well with missing
+                  ;; end-of-file newline, so add one
+                  (if (/= (char-after (1- (point-max))) ?\n)
+                      (save-excursion
+                        (goto-char (point-max))
+                        (insert ?\n)))
+
+                  (if (= 0 (shell-command-on-region (point-min) (point-max)
+                                                    (concat "gofmt" flag)
+                                                    patchbuf nil errbuf))
+                      ;; gofmt succeeded: replace buffer or apply patch hunks.
+                      (let ((old-point (point))
+                            (old-mark (mark t)))
+                        (kill-buffer errbuf)
+                        (if newfile
+                            ;; New file, replace it (diff-mode won't work)
+                            (gofmt-replace-buffer srcbuf patchbuf)
+                          ;; Existing file, patch it
+                          (gofmt-apply-patch filename srcbuf patchbuf))
+                        (goto-char (min old-point (point-max)))
+                        ;; Restore the mark and point
+                        (if old-mark (push-mark (min old-mark (point-max)) t))
+                        (set-window-configuration currconf))
+
+                    ;; gofmt failed: display the errors
+                    (gofmt-process-errors filename errbuf))))))
+
+          ;; Collapse any window opened on outbuf if shell-command-on-region
+          ;; displayed it.
+          (delete-windows-on patchbuf)))
+      (kill-buffer patchbuf))))
+
+(defun gofmt-replace-buffer (srcbuf patchbuf)
+  (with-current-buffer srcbuf
+    (erase-buffer)
+    (insert-buffer-substring patchbuf)))
+
+(defun gofmt-apply-patch (filename srcbuf patchbuf)
+  (require 'diff-mode)
+  ;; apply all the patch hunks
+  (with-current-buffer patchbuf
+    (goto-char (point-min))
+    ;; The .* is for TMPDIR, but to avoid dealing with TMPDIR
+    ;; having a trailing / or not, it's easier to just search for .*
+    ;; especially as we're only replacing the first instance.
+    (if (re-search-forward "^--- \\(.*/gofmt[0-9]*\\)" nil t)
+        (replace-match filename nil nil nil 1))
+    (condition-case nil
+        (while t
+          (diff-hunk-next)
+          (diff-apply-hunk))
+      ;; When there's no more hunks, diff-hunk-next signals an error, ignore it
+      (error nil))))
+
+(defun gofmt-process-errors (filename errbuf)
+  ;; Convert the gofmt stderr to something understood by the compilation mode.
+  (with-current-buffer errbuf
+    (goto-char (point-min))
+    (insert "gofmt errors:\n")
+    (if (search-forward gofmt-stdin-tag nil t)
+        (replace-match (file-name-nondirectory filename) nil t))
+    (display-buffer errbuf)
+    (compilation-mode)))
+
+;;;###autoload
+(defun gofmt-before-save ()
+  "Add this to .emacs to run gofmt on the current buffer when saving:
+ (add-hook 'before-save-hook 'gofmt-before-save)"
+
+  (interactive)
+  (when (eq major-mode 'go-mode) (gofmt)))
+
+(defun godoc-read-query ()
+  "Read a godoc query from the minibuffer."
+  ;; Compute the default query as the symbol under the cursor.
+  ;; TODO: This does the wrong thing for e.g. multipart.NewReader (it only 
grabs
+  ;; half) but I see no way to disambiguate that from e.g. foobar.SomeMethod.
+  (let* ((bounds (bounds-of-thing-at-point 'symbol))
+         (symbol (if bounds
+                     (buffer-substring-no-properties (car bounds)
+                                                     (cdr bounds)))))
+    (read-string (if symbol
+                     (format "godoc (default %s): " symbol)
+                   "godoc: ")
+                 nil nil symbol)))
+
+(defun godoc-get-buffer (query)
+  "Get an empty buffer for a godoc query."
+  (let* ((buffer-name (concat "*godoc " query "*"))
+         (buffer (get-buffer buffer-name)))
+    ;; Kill the existing buffer if it already exists.
+    (when buffer (kill-buffer buffer))
+    (get-buffer-create buffer-name)))
+
+(defun godoc-buffer-sentinel (proc event)
+  "Sentinel function run when godoc command completes."
+  (with-current-buffer (process-buffer proc)
+    (cond ((string= event "finished\n")  ;; Successful exit.
+           (goto-char (point-min))
+           (view-buffer (current-buffer) 'kill-buffer))
+          ((not (= (process-exit-status proc) 0))  ;; Error exit.
+           (let ((output (buffer-string)))
+             (kill-buffer (current-buffer))
+             (message (concat "godoc: " output)))))))
+
+;;;###autoload
+(defun godoc (query)
+  "Show go documentation for a query, much like M-x man."
+  (interactive (list (godoc-read-query)))
+  (unless (string= query "")
+    (set-process-sentinel
+     (start-process-shell-command "godoc" (godoc-get-buffer query)
+                                  (concat "godoc " query))
+     'godoc-buffer-sentinel)
+    nil))
+
+(defun go-goto-imports ()
+  (interactive)
+  ;; FIXME if there's a block-commented import before the real
+  ;; imports, we'll jump to that one.
+
+  ;; Generally, this function isn't very forgiving. it'll bark on
+  ;; extra whitespace. It works well for clean code.
+  (let ((old-point (point)))
+    (goto-char (point-min))
+    (cond
+     ((re-search-forward "^import ([^)]+)" nil t)
+      (backward-char 2))
+     ((re-search-forward "\\(^import \"[^\"]+\"\n?\\)+" nil t))
+     ((re-search-forward "^[[:space:]\n]*package .+?\n" nil t))
+     (t
+      (goto-char old-point)
+      (message "No imports found. Is this really a Go file?")))))
+
+
+;; "However, it should not call syntax-ppss-flush-cache; so, it is not allowed 
to call syntax-ppss on some position and later modify the buffer at an earlier 
position."
+;; ↑ let's hope this doesn't screw me over
+
+;; TODO do we have to deal with removing the text property again, too?
+;; and what happens when we edit a string? etc...
+;; FIXME make this work :D
+;; (set (make-local-variable 'syntax-propertize-function) 
'go-propertize-syntax)
+(defun go-propertize-syntax (start end)
+  (save-excursion
+    (let (start-of-string end-of-string)
+      (goto-char start)
+      ;; TODO loop this
+      (skip-chars-forward "^`" end)
+      (if (go-in-string-p)
+          (progn
+            (setq end-of-string (point))
+            (go-goto-beginning-of-string-or-comment)
+            (if (looking-at "`")
+                (progn
+                  (setq start-of-string (point))
+                  ;; (syntax-code . matching-char)
+                  (skip-chars-forward "^\\" end-of-string) ;; TODO loop this
+                  (if (looking-at "\\")
+                      (message "%s" (point))
+                    (put-text-property (1- (point)) (point) 'syntax-table 
(string-to-syntax "."))))))))))
+
+(defun go-common-prefix (sequences)
+  (assert sequences)
+  (flet ((common-prefix (s1 s2)
+                        (let ((diff-pos (mismatch s1 s2)))
+                          (if diff-pos (subseq s1 0 diff-pos) s1))))
+    (reduce #'common-prefix sequences)))
+
+
+
+(provide 'go-mode)
+



reply via email to

[Prev in Thread] Current Thread [Next in Thread]