1 new commit in XEmacs:
https://bitbucket.org/xemacs/xemacs/commits/aebf53236cff/
Changeset: aebf53236cff
User: matsl
Date: 2013-04-20 00:33:15
Summary: Updated ChangeLog about new unit test for file-attributes.
Should have gone in with previous commit.
Affected #: 1 file
diff -r c30fdcab7bc8eb4769a1a11d82d76bf20d6857c3 -r aebf53236cff0fee341e717cf3f8b74daeb4e838 tests/ChangeLog
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,7 @@
+2013-04-20 Mats Lidell <matsl(a)xemacs.org>
+
+ * automated/dired-tests.el: New. Tests for file-attributes.
+
2013-01-04 Stephen J. Turnbull <stephen(a)xemacs.org>
* XEmacs 21.5.33 "horseradish" is released.
Repository URL: https://bitbucket.org/xemacs/xemacs/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
_______________________________________________
XEmacs-Patches mailing list
XEmacs-Patches(a)xemacs.org
http://lists.xemacs.org/mailman/listinfo/xemacs-patches
1 new commit in xemacs-21.4:
https://bitbucket.org/xemacs/xemacs-21.4/commits/af4d0249573a/
Changeset: af4d0249573a
User: Vin Shelton
Date: 2013-04-19 05:05:34
Summary: Back out shifted function key hack
Affected #: 2 files
diff -r 13d13fa1974802424c254ff5e981d148f8163dcd -r af4d0249573a5ac5b34d257c1c0bcc6ec7f085ad src/ChangeLog
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,9 +1,3 @@
-2013-04-12 Vin Shelton <acs(a)xemacs.org>
-
- * event-Xt.c (x_event_to_emacs_event): Allow XEmacs to recognize
- shifted function keys directly. This is likely an XFree bug.
- Patch by Sean MacLennan.
-
2012-07-12 Vin Shelton <acs(a)xemacs.org>
* glyphs-eimage.c: Fix this so it compiles with libpng-1.5.10.
diff -r 13d13fa1974802424c254ff5e981d148f8163dcd -r af4d0249573a5ac5b34d257c1c0bcc6ec7f085ad src/event-Xt.c
--- a/src/event-Xt.c
+++ b/src/event-Xt.c
@@ -1260,25 +1260,7 @@
KeySym bot = XLookupKeysym (ev, Mode_switch_p ? 2 : 0);
KeySym top = XLookupKeysym (ev, Mode_switch_p ? 3 : 1);
if (top && bot && top != bot)
- /* Look directly for shifted function keycodes */
- switch(top) {
- case 0x1008fe01:
- case 0x1008fe02:
- case 0x1008fe03:
- case 0x1008fe04:
- case 0x1008fe05:
- case 0x1008fe06:
- case 0x1008fe07:
- case 0x1008fe08:
- case 0x1008fe09:
- case 0x1008fe0a:
- case 0x1008fe0b:
- case 0x1008fe0c:
- break;
- default:
- modifiers &= ~XEMACS_MOD_SHIFT;
- break;
- }
+ modifiers &= ~XEMACS_MOD_SHIFT;
}
emacs_event->event_type = key_press_event;
emacs_event->timestamp = ev->time;
Repository URL: https://bitbucket.org/xemacs/xemacs-21.4/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
_______________________________________________
XEmacs-Patches mailing list
XEmacs-Patches(a)xemacs.org
http://lists.xemacs.org/mailman/listinfo/xemacs-patches
1 new commit in hyperbole:
https://bitbucket.org/xemacs/hyperbole/commits/341eb618abad/
Changeset: 341eb618abad
User: matsl
Date: 2013-04-14 14:42:29
Summary: Synced with FSF version 5.0.4.
This version bump is mostly because a new release was needed to solve
a security issue with the automake generated files in the
distribution.
Affected #: 6 files
diff -r 08dc729d2781ba4b30cdbddb6a434e0dd169f129 -r 341eb618abad9807a26e6cb7364b73be406bf5c6 ChangeLog
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2013-04-14 Mats Lidell <matsl(a)xemacs.org>
+
+ * Synced with FSF version 5.0.4
+
2012-01-13 Norbert Koch <viteno(a)xemacs.org>
* Makefile (VERSION): XEmacs package 1.18 released.
diff -r 08dc729d2781ba4b30cdbddb6a434e0dd169f129 -r 341eb618abad9807a26e6cb7364b73be406bf5c6 Changelog.hypb
--- a/Changelog.hypb
+++ b/Changelog.hypb
@@ -1,3 +1,16 @@
+2013-03-28 Mats Lidell <mats.lidell(a)cag.se>
+
+ * make-dist: Use mercurial to get the sources for making the
+ distribution.
+
+ * 5.0.4 released
+
+ * hversion.el (hyperb:version): Version bumpt to 5.0.4
+ * configure.ac: ditto.
+ * man/version.texi: ditto.
+ * NEWS: ditto.
+ * README: ditto.
+
2009-10-24 Mats Lidell <matsl(a)contactor.se>
* hui-xe-but.el (hproperty:set-face-after-init): Set button faces
diff -r 08dc729d2781ba4b30cdbddb6a434e0dd169f129 -r 341eb618abad9807a26e6cb7364b73be406bf5c6 NEWS
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,16 @@
See "ChangeLog" for a detailed view of the changes.
===========================================================================
+* V5.0.4
+===========================================================================
+
+ GENERAL
+
+ This relase fixes a security problem in Automake-generated
+ Makefiles.
+
+
+===========================================================================
* V5.0.3
===========================================================================
diff -r 08dc729d2781ba4b30cdbddb6a434e0dd169f129 -r 341eb618abad9807a26e6cb7364b73be406bf5c6 README
--- a/README
+++ b/README
@@ -150,10 +150,10 @@
===========================================================================
-* What's New in V5.0.3?
+* What's New in V5.0.4?
===========================================================================
-Version 5.0.3 adds support for ibuffer and fixes some bugs.
+Version 5.0.4 fixes a security problem with Automake-generated Makefiles.
See "ChangeLog" and "NEWS" for more complete details of changes.
diff -r 08dc729d2781ba4b30cdbddb6a434e0dd169f129 -r 341eb618abad9807a26e6cb7364b73be406bf5c6 hversion.el
--- a/hversion.el
+++ b/hversion.el
@@ -33,7 +33,7 @@
;;; Public variables
;;;
-(defconst hyperb:version "5.0.3" "Hyperbole revision number.")
+(defconst hyperb:version "5.0.4" "Hyperbole revision number.")
;;; Support button highlighting and flashing under XEmacs.
;;;
diff -r 08dc729d2781ba4b30cdbddb6a434e0dd169f129 -r 341eb618abad9807a26e6cb7364b73be406bf5c6 man/version.texi
--- a/man/version.texi
+++ b/man/version.texi
@@ -1,4 +1,4 @@
@set UPDATED 8 August 2008
@set UPDATED-MONTH August 2008
-@set EDITION 5.0.3
-@set VERSION 5.0.3
+@set EDITION 5.0.4
+@set VERSION 5.0.4
Repository URL: https://bitbucket.org/xemacs/hyperbole/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
_______________________________________________
XEmacs-Patches mailing list
XEmacs-Patches(a)xemacs.org
http://lists.xemacs.org/mailman/listinfo/xemacs-patches
1 new commit in prog-modes:
https://bitbucket.org/xemacs/prog-modes/commits/226ae620b716/
Changeset: 226ae620b716
User: matsl
Date: 2013-04-14 13:44:44
Summary: go-mode.el: Sync with upstream version 16503.
Affected #: 3 files
diff -r e5d5caa0c9c68f304f2ed904106843ce5cb1d535 -r 226ae620b7169243c2f8a508eda870fd3cb16f8a ChangeLog
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2013-04-14 Mats Lidell <matsl(a)xemacs.org>
+
+ * Makefile (REQUIRES): Added gnus and w3 for new go-mode.
+ * go-mode.el: Sync with upstream version 16503.
+
2012-12-16 Norbert Koch <viteno(a)xemacs.org>
* Makefile (VERSION): XEmacs package 2.28 released.
diff -r e5d5caa0c9c68f304f2ed904106843ce5cb1d535 -r 226ae620b7169243c2f8a508eda870fd3cb16f8a Makefile
--- a/Makefile
+++ b/Makefile
@@ -24,7 +24,7 @@
PKG_TYPE = single-file
REQUIRES = mail-lib xemacs-devel xemacs-base cc-mode \
fsf-compat edit-utils ediff emerge efs vc speedbar dired \
- ilisp sh-script cedet-common
+ ilisp sh-script cedet-common w3 gnus
CATEGORY = standard
ELCS = asm-mode.elc autoconf-mode.elc awk-mode.elc cl-indent.elc \
diff -r e5d5caa0c9c68f304f2ed904106843ce5cb1d535 -r 226ae620b7169243c2f8a508eda870fd3cb16f8a go-mode.el
--- a/go-mode.el
+++ b/go-mode.el
@@ -1,6 +1,6 @@
;;; go-mode.el --- Major mode for the Go programming language
-;; Copyright (c) 2012 The Go Authors. All rights reserved.
+;; Copyright (c) 2013 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
@@ -28,43 +28,115 @@
;; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
;; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-;;; Synced up with: upstream go-mode.el 14989:a522fb590152
+;;; Synced up with: upstream go-mode.el 16503:45a52c375f4f
-;;; Commentary:
+(require 'cl)
+(require 'ffap)
+(require 'url)
-;; For installation instructions, see go-mode-load.el
+;; XEmacs compatibility guidelines
+;; - Minimum required version of XEmacs: 21.5.32
+;; - Feature that cannot be backported: POSIX character classes in
+;; regular expressions
+;; - Functions that could be backported but won't because 21.5.32
+;; covers them: plenty.
+;; - Features that are still partly broken:
+;; - godef will not work correctly if multibyte characters are
+;; being used
+;; - Fontification will not handle unicode correctly
+;;
+;; - Do not use \_< and \_> regexp delimiters directly; use
+;; go--regexp-enclose-in-symbol
+;;
+;; - The character `_` must not be a symbol constituent but a
+;; character constituent
+;;
+;; - Do not use process-lines
+;;
+;; - Use go--old-completion-list-style when using a plain list as the
+;; collection for completing-read
+;;
+;; - Use go--kill-whole-line instead of kill-whole-line (called
+;; kill-entire-line in XEmacs)
+;;
+;; - Use go--position-bytes instead of position-bytes
+(defmacro go--xemacs-p ()
+ `(featurep 'xemacs))
-;;; To do:
+(defalias 'go--kill-whole-line
+ (if (fboundp 'kill-whole-line)
+ 'kill-whole-line
+ 'kill-entire-line))
-;; * Indentation is *almost* identical to gofmt
-;; ** We think struct literal keys are labels and outdent them
-;; ** We disagree on the indentation of function literals in arguments
-;; ** There are bugs with the close brace of struct literals
-;; * Highlight identifiers according to their syntactic context: type,
-;; variable, function call, or tag
-;; * Command for adding an import
-;; ** Check if it's already there
-;; ** Factor/unfactor the import line
-;; ** Alphabetize
-;; * Remove unused imports
-;; ** This is hard, since I have to be aware of shadowing to do it
-;; right
-;; * Format region using gofmt
+;; XEmacs unfortunately does not offer position-bytes. We can fall
+;; back to just using (point), but it will be incorrect as soon as
+;; multibyte characters are being used.
+(if (fboundp 'position-bytes)
+ (defalias 'go--position-bytes 'position-bytes)
+ (defun go--position-bytes (point) point))
-;;; Code:
+(defun go--old-completion-list-style (list)
+ (mapcar (lambda (x) (cons x nil)) list))
-(eval-when-compile (require 'cl))
+;; GNU Emacs 24 has prog-mode, older GNU Emacs and XEmacs do not.
+;; Ideally we'd use defalias instead, but that breaks in XEmacs.
+;;
+;; TODO: If XEmacs decides to add prog-mode, change this to use
+;; defalias to alias prog-mode or fundamental-mode to go--prog-mode
+;; and use that in define-derived-mode.
+(if (not (fboundp 'prog-mode))
+ (define-derived-mode prog-mode fundamental-mode "" ""))
+
+(defun go--regexp-enclose-in-symbol (s)
+ ;; XEmacs does not support \_<, GNU Emacs does. In GNU Emacs we make
+ ;; extensive use of \_< to support unicode in identifiers. Until we
+ ;; come up with a better solution for XEmacs, this solution will
+ ;; break fontification in XEmacs for identifiers such as "typeµ".
+ ;; XEmacs will consider "type" a keyword, GNU Emacs won't.
+
+ (if (go--xemacs-p)
+ (concat "\\<" s "\\>")
+ (concat "\\_<" s "\\_>")))
+
+(defconst go-dangling-operators-regexp "[^-]-\\|[^+]\\+\\|[/*&><.=|^]")
+(defconst go-identifier-regexp "[[:word:][:multibyte:]]+")
+(defconst go-label-regexp go-identifier-regexp)
+(defconst go-type-regexp "[[:word:][:multibyte:]*]+")
+(defconst go-func-regexp (concat (go--regexp-enclose-in-symbol "func") "\\s *\\(" go-identifier-regexp "\\)"))
+(defconst go-func-meth-regexp (concat (go--regexp-enclose-in-symbol "func") "\\s *\\(?:(\\s *" go-identifier-regexp "\\s +" go-type-regexp "\\s *)\\s *\\)?\\(" go-identifier-regexp "\\)("))
+(defconst go-builtins
+ '("append" "cap" "close" "complex" "copy"
+ "delete" "imag" "len" "make" "new"
+ "panic" "print" "println" "real" "recover")
+ "All built-in functions in the Go language. Used for font locking.")
+
+(defconst 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.")
+
+(defconst go-constants '("nil" "true" "false" "iota"))
+(defconst go-type-name-regexp (concat "\\(?:[*(]\\)*\\(?:" go-identifier-regexp "\\.\\)?\\(" go-identifier-regexp "\\)"))
+
+(defvar go-dangling-cache)
+(defvar go-godoc-history nil)
+
+(defgroup go nil
+ "Major mode for editing Go code"
+:group 'languages)
+
+(defcustom go-fontify-function-calls t
+ "Fontify function and method calls if this is non-nil."
+:type 'boolean
+:group 'go)
(defvar go-mode-syntax-table
(let ((st (make-syntax-table)))
- ;; Add _ to :word: character class
- (modify-syntax-entry ?_ "w" st)
-
- ;; Operators (punctuation)
(modify-syntax-entry ?+ "." st)
(modify-syntax-entry ?- "." st)
- (modify-syntax-entry ?* ". 23" st) ; also part of comments
- (modify-syntax-entry ?/ (if (featurep 'xemacs) ". 1456" ". 124b") st) ; ditto
(modify-syntax-entry ?% "." st)
(modify-syntax-entry ?& "." st)
(modify-syntax-entry ?| "." st)
@@ -73,80 +145,62 @@
(modify-syntax-entry ?= "." st)
(modify-syntax-entry ?< "." st)
(modify-syntax-entry ?> "." st)
-
- ;; Strings and comments are font-locked separately.
- (modify-syntax-entry ?\" "." st)
- (modify-syntax-entry ?\' "." st)
- (modify-syntax-entry ?` "." st)
- (modify-syntax-entry ?\\ "." st)
-
- ;; Newline is a comment-ender.
+ (modify-syntax-entry ?/ (if (go--xemacs-p) ". 1456" ". 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)
+ ;; It would be nicer to have _ as a symbol constituent, but that
+ ;; would trip up XEmacs, which does not support the \_< anchor
+ (modify-syntax-entry ?_ "w" 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.")
+(defun go--build-font-lock-keywords ()
+ ;; we cannot use 'symbols in regexp-opt because emacs <24 doesn't
+ ;; understand that
+ (append
+ `((,(go--regexp-enclose-in-symbol (regexp-opt go-mode-keywords t)) . font-lock-keyword-face)
+ (,(go--regexp-enclose-in-symbol (regexp-opt go-builtins t)) . font-lock-builtin-face)
+ (,(go--regexp-enclose-in-symbol (regexp-opt go-constants t)) . font-lock-constant-face)
+ (,go-func-regexp 1 font-lock-function-name-face)) ;; function (not method) name
-(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 "\\s *\\(?:[*(]\\s *\\)*\\(?:\\w+\\s *\\.\\s *\\)?\\(\\w+\\)")
- )
- `((go-mode-font-lock-cs-comment 0 font-lock-comment-face t)
- (go-mode-font-lock-cs-string 0 font-lock-string-face t)
- (,(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)
- ;; Function names in declarations
- ("\\<func\\>\\s *\\(\\w+\\)" 1 font-lock-function-name-face)
- ;; Function names in methods are handled by function call pattern
- ;; Function names in calls
- ;; XXX Doesn't match if function name is surrounded by parens
- ("\\(\\w+\\)\\s *(" 1 font-lock-function-name-face)
- ;; Type names
- ("\\<type\\>\\s *\\(\\w+\\)" 1 font-lock-type-face)
- (,(concat "\\<type\\>\\s *\\w+\\s *" type-name) 1 font-lock-type-face)
- ;; Arrays/slices/map value type
- ;; XXX Wrong. Marks 0 in expression "foo[0] * x"
- ;; (,(concat "]" type-name) 1 font-lock-type-face)
- ;; Map key type
- (,(concat "\\<map\\s *\\[" type-name) 1 font-lock-type-face)
- ;; Channel value type
- (,(concat "\\<chan\\>\\s *\\(?:<-\\)?" type-name) 1 font-lock-type-face)
- ;; new/make type
- (,(concat "\\<\\(?:new\\|make\\)\\>\\(?:\\s \\|)\\)*(" type-name) 1 font-lock-type-face)
- ;; Type conversion
- (,(concat "\\.\\s *(" type-name) 1 font-lock-type-face)
- ;; Method receiver type
- (,(concat "\\<func\\>\\s *(\\w+\\s +" type-name) 1 font-lock-type-face)
- ;; Labels
- ;; XXX Not quite right. Also marks compound literal fields.
- ("^\\s *\\(\\w+\\)\\s *:\\(\\S.\\|$\\)" 1 font-lock-constant-face)
- ("\\<\\(goto\\|break\\|continue\\)\\>\\s *\\(\\w+\\)" 2 font-lock-constant-face)))
- "Basic font lock keywords for Go mode. Highlights keywords,
-built-ins, functions, and some types.")
+ (if go-fontify-function-calls
+ `((,(concat "\\(" go-identifier-regexp "\\)[[:space:]]*(") 1 font-lock-function-name-face) ;; function call/method name
+ (,(concat "(\\(" go-identifier-regexp "\\))[[:space:]]*(") 1 font-lock-function-name-face)) ;; bracketed function call
+ `((,go-func-meth-regexp 1 font-lock-function-name-face))) ;; method name
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Key map
-;;
+ `(
+ (,(concat (go--regexp-enclose-in-symbol "type") "[[:space:]]*\\([^[:space:]]+\\)") 1 font-lock-type-face) ;; types
+ (,(concat (go--regexp-enclose-in-symbol "type") "[[:space:]]*" go-identifier-regexp "[[:space:]]*" go-type-name-regexp) 1 font-lock-type-face) ;; types
+ (,(concat "[^[:word:][:multibyte:]]\\[\\([[:digit:]]+\\|\\.\\.\\.\\)?\\]" go-type-name-regexp) 2 font-lock-type-face) ;; Arrays/slices
+ (,(concat "\\(" go-identifier-regexp "\\)" "{") 1 font-lock-type-face)
+ (,(concat (go--regexp-enclose-in-symbol "map") "\\[[^]]+\\]" go-type-name-regexp) 1 font-lock-type-face) ;; map value type
+ (,(concat (go--regexp-enclose-in-symbol "map") "\\[" go-type-name-regexp) 1 font-lock-type-face) ;; map key type
+ (,(concat (go--regexp-enclose-in-symbol "chan") "[[:space:]]*\\(?:<-\\)?" go-type-name-regexp) 1 font-lock-type-face) ;; channel type
+ (,(concat (go--regexp-enclose-in-symbol "\\(?:new\\|make\\)") "\\(?:[[:space:]]\\|)\\)*(" go-type-name-regexp) 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 *(" go-type-name-regexp) 1 font-lock-type-face) ;; Type conversion
+ (,(concat (go--regexp-enclose-in-symbol "func") "[[:space:]]+(" go-identifier-regexp "[[:space:]]+" go-type-name-regexp ")") 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.
+ (,(concat "^[[:space:]]*\\(" go-label-regexp "\\)[[:space:]]*:\\(\\S.\\|$\\)") 1 font-lock-constant-face) ;; Labels and compound literal fields
+ (,(concat (go--regexp-enclose-in-symbol "\\(goto\\|break\\|continue\\)") "[[:space:]]*\\(" go-label-regexp "\\)") 2 font-lock-constant-face)))) ;; labels in goto/break/continue
(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-delayed-electric)
- ;; In case we get : indentation wrong, correct ourselves
- (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)
+ (define-key m "=" 'go-mode-insert-and-indent)
+ (define-key m (kbd "C-c C-a") 'go-import-add)
+ (define-key m (kbd "C-c C-j") 'godef-jump)
+ (define-key m (kbd "C-c C-d") 'godef-describe)
m)
"Keymap used by Go mode to implement electric keys.")
@@ -157,606 +211,279 @@
(call-interactively (lookup-key (current-global-map) key))
(indent-according-to-mode))
-(defvar go-mode-delayed-point nil
- "The point following the previous insertion if the insertion
-was a delayed electric key. Used to communicate between
-`go-mode-delayed-electric' and `go-mode-delayed-electric-hook'.")
-(make-variable-buffer-local 'go-mode-delayed-point)
+(defmacro go-paren-level ()
+ `(car (syntax-ppss)))
-(defun go-mode-delayed-electric (p)
- "Perform electric insertion, but delayed by one event.
+(defmacro go-in-string-or-comment-p ()
+ `(nth 8 (syntax-ppss)))
-This inserts P into the buffer, as usual, then waits for another key.
-If that second key causes a buffer modification starting at the
-point after the insertion of P, reindents the line containing P."
+(defmacro go-in-string-p ()
+ `(nth 3 (syntax-ppss)))
- (interactive "p")
- (self-insert-command p)
- (setq go-mode-delayed-point (point)))
+(defmacro go-in-comment-p ()
+ `(nth 4 (syntax-ppss)))
-(defun go-mode-delayed-electric-hook (b e l)
- "An after-change-function that implements `go-mode-delayed-electric'."
+(defmacro go-goto-beginning-of-string-or-comment ()
+ `(goto-char (nth 8 (syntax-ppss))))
- (when (and go-mode-delayed-point
- (= go-mode-delayed-point b))
- (save-excursion
- (save-match-data
- (goto-char go-mode-delayed-point)
- (indent-according-to-mode))))
- (setq go-mode-delayed-point nil))
+(defun go--backward-irrelevant (&optional stop-at-string)
+ "Skips backwards over any characters that are irrelevant for
+indentation and related tasks.
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Parser
-;;
+It skips over whitespace, comments, cases and labels and, if
+STOP-AT-STRING is not true, over strings."
-(defvar go-mode-mark-cs-end 1
- "The point at which the comment/string cache ends. The buffer
-will be marked from the beginning up to this point (that is, up
-to and including character (1- go-mode-mark-cs-end)).")
-(make-variable-buffer-local 'go-mode-mark-cs-end)
+ (let (pos (start-pos (point)))
+ (skip-chars-backward "\n\s\t")
+ (if (and (save-excursion (beginning-of-line) (go-in-string-p)) (looking-back "`") (not stop-at-string))
+ (backward-char))
+ (if (and (go-in-string-p) (not stop-at-string))
+ (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 (concat "^" go-label-regexp ":")) (looking-at "^[[:space:]]*\\(case .+\\|default\\):"))
+ (end-of-line 0)
+ (goto-char pos))
+ (if (/= start-pos (point))
+ (go--backward-irrelevant stop-at-string))
+ (/= start-pos (point))))
-(defvar go-mode-mark-string-end 1
- "The point at which the string cache ends. The buffer
-will be marked from the beginning up to this point (that is, up
-to and including character (1- go-mode-mark-string-end)).")
-(make-variable-buffer-local 'go-mode-mark-string-end)
+(defun go--buffer-narrowed-p ()
+ "Return non-nil if the current buffer is narrowed."
+ (/= (buffer-size)
+ (- (point-max)
+ (point-min))))
-(defvar go-mode-mark-comment-end 1
- "The point at which the comment cache ends. The buffer
-will be marked from the beginning up to this point (that is, up
-to and including character (1- go-mode-mark-comment-end)).")
-(make-variable-buffer-local 'go-mode-mark-comment-end)
+(defun go-previous-line-has-dangling-op-p ()
+ "Returns non-nil if the current line is a continuation line."
+ (let* ((cur-line (line-number-at-pos))
+ (val (gethash cur-line go-dangling-cache 'nope)))
+ (if (or (go--buffer-narrowed-p) (equal val 'nope))
+ (save-excursion
+ (beginning-of-line)
+ (go--backward-irrelevant t)
+ (setq val (looking-back go-dangling-operators-regexp))
+ (if (not (go--buffer-narrowed-p))
+ (puthash cur-line val go-dangling-cache))))
+ val))
-(defvar go-mode-mark-nesting-end 1
- "The point at which the nesting cache ends. The buffer will be
-marked from the beginning up to this point.")
-(make-variable-buffer-local 'go-mode-mark-nesting-end)
+(defun go--at-function-definition ()
+ "Return non-nil if point is on the opening curly brace of a
+function definition.
-(defun go-mode-mark-clear-cs (b e l)
- "An after-change-function that removes the go-mode-cs text property"
- (remove-text-properties b e '(go-mode-cs)))
+We do this by first calling (beginning-of-defun), which will take
+us to the start of *some* function. We then look for the opening
+curly brace of that function and compare its position against the
+curly brace we are checking. If they match, we return non-nil."
+ (if (= (char-after) ?\{)
+ (save-excursion
+ (let ((old-point (point))
+ start-nesting)
+ (beginning-of-defun)
+ (when (looking-at "func ")
+ (setq start-nesting (go-paren-level))
+ (skip-chars-forward "^{")
+ (while (> (go-paren-level) start-nesting)
+ (forward-char)
+ (skip-chars-forward "^{") 0)
+ (if (and (= (go-paren-level) start-nesting) (= old-point (point)))
+ t))))))
-(defun go-mode-mark-clear-cache (b e)
- "A before-change-function that clears the comment/string and
-nesting caches from the modified point on."
+(defun go-goto-opening-parenthesis (&optional char)
+ (let ((start-nesting (go-paren-level)))
+ (while (and (not (bobp))
+ (>= (go-paren-level) start-nesting))
+ (if (zerop (skip-chars-backward
+ (if char
+ (case char (?\] "^[") (?\} "^{") (?\) "^("))
+ "^[{(")))
+ (if (go-in-string-or-comment-p)
+ (go-goto-beginning-of-string-or-comment)
+ (backward-char))))))
- (save-restriction
- (widen)
- (when (<= b go-mode-mark-cs-end)
- ;; Remove the property adjacent to the change position.
- ;; It may contain positions pointing beyond the new end mark.
- (let ((b (let ((cs (get-text-property (max 1 (1- b)) 'go-mode-cs)))
- (if cs (car cs) b))))
- (remove-text-properties
- b (min go-mode-mark-cs-end (point-max)) '(go-mode-cs nil))
- (setq go-mode-mark-cs-end b)))
+(defun go--indentation-for-opening-parenthesis ()
+ "Return the semantic indentation for the current opening parenthesis.
- (when (<= b go-mode-mark-string-end)
- ;; Remove the property adjacent to the change position.
- ;; It may contain positions pointing beyond the new end mark.
- (let ((b (let ((cs (get-text-property (max 1 (1- b)) 'go-mode-string)))
- (if cs (car cs) b))))
- (remove-text-properties
- b (min go-mode-mark-string-end (point-max)) '(go-mode-string nil))
- (setq go-mode-mark-string-end b)))
- (when (<= b go-mode-mark-comment-end)
- ;; Remove the property adjacent to the change position.
- ;; It may contain positions pointing beyond the new end mark.
- (let ((b (let ((cs (get-text-property (max 1 (1- b)) 'go-mode-comment)))
- (if cs (car cs) b))))
- (remove-text-properties
- b (min go-mode-mark-string-end (point-max)) '(go-mode-comment nil))
- (setq go-mode-mark-comment-end b)))
+If point is on an opening curly brace and said curly brace
+belongs to a function declaration, the indentation of the func
+keyword will be returned. Otherwise the indentation of the
+current line will be returned."
+ (save-excursion
+ (if (go--at-function-definition)
+ (progn
+ (beginning-of-defun)
+ (current-indentation))
+ (current-indentation))))
- (when (< b go-mode-mark-nesting-end)
- (remove-text-properties b (min go-mode-mark-nesting-end (point-max)) '(go-mode-nesting nil))
- (setq go-mode-mark-nesting-end b))))
+(defun go-indentation-at-point ()
+ (save-excursion
+ (let (start-nesting (outindent 0))
+ (back-to-indentation)
+ (setq start-nesting (go-paren-level))
-(defmacro go-mode-parser (&rest body)
- "Evaluate BODY in an environment set up for parsers that use
-text properties to mark text. This inhibits changes to the undo
-list or the buffer's modification status and inhibits calls to
-the modification hooks. It also saves the excursion and
-restriction and widens the buffer, since most parsers are
-context-sensitive."
-
- (let ((modified-var (make-symbol "modified")))
- `(let ((buffer-undo-list t)
- (,modified-var (buffer-modified-p))
- (inhibit-modification-hooks t)
- (inhibit-read-only t))
- (save-excursion
- (save-restriction
- (widen)
- (unwind-protect
- (progn ,@body)
- (set-buffer-modified-p ,modified-var)))))))
-
-(defun go-mode-cs (&optional pos)
- "Return the comment/string state at point POS. If point is
-inside a comment or string (including the delimiters), this
-returns a pair (START . END) indicating the extents of the
-comment or string."
-
- (unless pos
- (setq pos (point)))
- (when (>= pos go-mode-mark-cs-end)
- (go-mode-mark-cs (1+ pos)))
- (get-text-property pos 'go-mode-cs))
-
-(defun go-mode-mark-cs (end)
- "Mark comments and strings up to point END. Don't call this
-directly; use `go-mode-cs'."
- (setq end (min end (point-max)))
- (go-mode-parser
- (save-match-data
- (let ((pos
- ;; Back up to the last known state.
- (let ((last-cs
- (and (> go-mode-mark-cs-end 1)
- (get-text-property (1- go-mode-mark-cs-end)
- 'go-mode-cs))))
- (if last-cs
- (car last-cs)
- (max 1 (1- go-mode-mark-cs-end))))))
- (while (< pos end)
- (goto-char pos)
- (let ((cs-end ; end of the text property
- (cond
- ((looking-at "//")
- (end-of-line)
- (1+ (point)))
- ((looking-at "/\\*")
- (goto-char (+ pos 2))
- (if (search-forward "*/" (1+ end) t)
- (point)
- end))
- ((looking-at "\"")
- (goto-char (1+ pos))
- (if (looking-at "[^\"\n\\\\]*\\(\\\\.[^\"\n\\\\]*\\)*\"")
- (match-end 0)
- (end-of-line)
- (point)))
- ((looking-at "'")
- (goto-char (1+ pos))
- (if (looking-at "[^'\n\\\\]*\\(\\\\.[^'\n\\\\]*\\)*'")
- (match-end 0)
- (end-of-line)
- (point)))
- ((looking-at "`")
- (goto-char (1+ pos))
- (while (if (search-forward "`" end t)
- (if (eq (char-after) ?`)
- (goto-char (1+ (point))))
- (goto-char end)
- nil))
- (point)))))
- (cond
- (cs-end
- (put-text-property pos cs-end 'go-mode-cs (cons pos cs-end))
- (setq pos cs-end))
- ((re-search-forward "[\"'`]\\|/[/*]" end t)
- (setq pos (match-beginning 0)))
- (t
- (setq pos end)))))
- (setq go-mode-mark-cs-end pos)))))
-
-(defun go-mode-in-comment (&optional pos)
- "Return the comment/string state at point POS. If point is
-inside a comment (including the delimiters), this
-returns a pair (START . END) indicating the extents of the
-comment or string."
-
- (unless pos
- (setq pos (point)))
- (when (> pos go-mode-mark-comment-end)
- (go-mode-mark-comment pos))
- (get-text-property pos 'go-mode-comment))
-
-(defun go-mode-mark-comment (end)
- "Mark comments up to point END. Don't call this directly; use `go-mode-in-comment'."
- (setq end (min end (point-max)))
- (go-mode-parser
- (save-match-data
- (let ((pos
- ;; Back up to the last known state.
- (let ((last-comment
- (and (> go-mode-mark-comment-end 1)
- (get-text-property (1- go-mode-mark-comment-end)
- 'go-mode-comment))))
- (if last-comment
- (car last-comment)
- (max 1 (1- go-mode-mark-comment-end))))))
- (while (< pos end)
- (goto-char pos)
- (let ((comment-end ; end of the text property
- (cond
- ((looking-at "//")
- (end-of-line)
- (1+ (point)))
- ((looking-at "/\\*")
- (goto-char (+ pos 2))
- (if (search-forward "*/" (1+ end) t)
- (point)
- end)))))
- (cond
- (comment-end
- (put-text-property pos comment-end 'go-mode-comment (cons pos comment-end))
- (setq pos comment-end))
- ((re-search-forward "/[/*]" end t)
- (setq pos (match-beginning 0)))
- (t
- (setq pos end)))))
- (setq go-mode-mark-comment-end pos)))))
-
-(defun go-mode-in-string (&optional pos)
- "Return the string state at point POS. If point is
-inside a string (including the delimiters), this
-returns a pair (START . END) indicating the extents of the
-comment or string."
-
- (unless pos
- (setq pos (point)))
- (when (> pos go-mode-mark-string-end)
- (go-mode-mark-string pos))
- (get-text-property pos 'go-mode-string))
-
-(defun go-mode-mark-string (end)
- "Mark strings up to point END. Don't call this
-directly; use `go-mode-in-string'."
- (setq end (min end (point-max)))
- (go-mode-parser
- (save-match-data
- (let ((pos
- ;; Back up to the last known state.
- (let ((last-cs
- (and (> go-mode-mark-string-end 1)
- (get-text-property (1- go-mode-mark-string-end)
- 'go-mode-string))))
- (if last-cs
- (car last-cs)
- (max 1 (1- go-mode-mark-string-end))))))
- (while (< pos end)
- (goto-char pos)
- (let ((cs-end ; end of the text property
- (cond
- ((looking-at "\"")
- (goto-char (1+ pos))
- (if (looking-at "[^\"\n\\\\]*\\(\\\\.[^\"\n\\\\]*\\)*\"")
- (match-end 0)
- (end-of-line)
- (point)))
- ((looking-at "'")
- (goto-char (1+ pos))
- (if (looking-at "[^'\n\\\\]*\\(\\\\.[^'\n\\\\]*\\)*'")
- (match-end 0)
- (end-of-line)
- (point)))
- ((looking-at "`")
- (goto-char (1+ pos))
- (while (if (search-forward "`" end t)
- (if (eq (char-after) ?`)
- (goto-char (1+ (point))))
- (goto-char end)
- nil))
- (point)))))
- (cond
- (cs-end
- (put-text-property pos cs-end 'go-mode-string (cons pos cs-end))
- (setq pos cs-end))
- ((re-search-forward "[\"'`]" end t)
- (setq pos (match-beginning 0)))
- (t
- (setq pos end)))))
- (setq go-mode-mark-string-end pos)))))
-
-(defun go-mode-font-lock-cs (limit comment)
- "Helper function for highlighting comment/strings. If COMMENT is t,
-set match data to the next comment after point, and advance point
-after it. If COMMENT is nil, use the next string. Returns nil
-if no further tokens of the type exist."
- ;; Ensures that `next-single-property-change' below will work properly.
- (go-mode-cs limit)
- (let (cs next (result 'scan))
- (while (eq result 'scan)
- (if (or (>= (point) limit) (eobp))
- (setq result nil)
- (setq cs (go-mode-cs))
- (if (and cs (>= (car cs) (point)))
- (if (eq (= (char-after (car cs)) ?/) comment)
- ;; If inside the expected comment/string, highlight it.
- (progn
- ;; If the match includes a "\n", we have a
- ;; multi-line construct. Mark it as such.
- (goto-char (car cs))
- (when (search-forward "\n" (cdr cs) t)
- (put-text-property
- (car cs) (cdr cs) 'font-lock-multline t))
- (set-match-data (list (car cs) (copy-marker (cdr cs))))
- (goto-char (cdr cs))
- (setq result t))
- ;; Wrong type. Look for next comment/string after this one.
- (goto-char (cdr cs)))
- ;; Not inside comment/string. Search for next comment/string.
- (setq next (next-single-property-change
- (point) 'go-mode-cs nil limit))
- (if (and next (< next limit))
- (goto-char next)
- (setq result nil)))))
- result))
-
-(defun go-mode-font-lock-cs-string (limit)
- "Font-lock iterator for strings."
- (go-mode-font-lock-cs limit nil))
-
-(defun go-mode-font-lock-cs-comment (limit)
- "Font-lock iterator for comments."
- (go-mode-font-lock-cs limit t))
-
-(defsubst go-mode-nesting (&optional pos)
- "Return the nesting at point POS. The nesting is a list
-of (START . END) pairs for all braces, parens, and brackets
-surrounding POS, starting at the inner-most nesting. START is
-the location of the open character. END is the location of the
-close character or nil if the nesting scanner has not yet
-encountered the close character."
-
- (unless pos
- (setq pos (point)))
- (if (= pos 1)
- '()
- (when (> pos go-mode-mark-nesting-end)
- (go-mode-mark-nesting pos))
- (get-text-property (- pos 1) 'go-mode-nesting)))
-
-(defun go-mode-mark-nesting (pos)
- "Mark nesting up to point END. Don't call this directly; use
-`go-mode-nesting'."
-
- (go-mode-cs pos)
- (go-mode-parser
- ;; Mark depth
- (goto-char go-mode-mark-nesting-end)
- (let ((nesting (go-mode-nesting))
- (last (point)))
- (while (< last pos)
- ;; Find the next depth-changing character
- (skip-chars-forward "^(){}[]" pos)
- ;; Mark everything up to this character with the current
- ;; nesting
- (put-text-property last (point) 'go-mode-nesting nesting)
- (when nil
- (let ((depth (length nesting)))
- (put-text-property last (point) 'face
- `((:background
- ,(format "gray%d" (* depth 10)))))))
- (setq last (point))
- ;; Update nesting
- (unless (eobp)
- (let ((ch (unless (go-mode-cs) (char-after))))
- (forward-char 1)
- (case ch
- ((?\( ?\{ ?\[)
- (setq nesting (cons (cons (- (point) 1) nil)
- nesting)))
- ((?\) ?\} ?\])
- (when nesting
- (setcdr (car nesting) (- (point) 1))
- (setq nesting (cdr nesting))))))))
- ;; Update state
- (setq go-mode-mark-nesting-end last))))
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Indentation
-;;
-
-(defvar go-mode-non-terminating-keywords-regexp
- (let* ((kws go-mode-keywords)
- (kws (remove "break" kws))
- (kws (remove "continue" kws))
- (kws (remove "fallthrough" kws))
- (kws (remove "return" kws)))
- (regexp-opt kws 'words))
- "Regular expression matching all Go keywords that *do not*
-implicitly terminate a statement.")
-
-(defun go-mode-semicolon-p ()
- "True iff point immediately follows either an explicit or
-implicit semicolon. Point should immediately follow the last
-token on the line."
-
- ;; #Semicolons
- (case (char-before)
- ((?\;) t)
- ;; String literal
- ((?' ?\" ?`) t)
- ;; One of the operators and delimiters ++, --, ), ], or }
- ((?+) (eq (char-before (1- (point))) ?+))
- ((?-) (eq (char-before (1- (point))) ?-))
- ((?\) ?\] ?\}) t)
- ;; An identifier or one of the keywords break, continue,
- ;; fallthrough, or return or a numeric literal
- (otherwise
- (save-excursion
- (when (/= (skip-chars-backward "[:word:]_") 0)
- (not (looking-at go-mode-non-terminating-keywords-regexp)))))))
-
-(defun go-mode-whitespace-p (char)
- "Is newline, or char whitespace in the syntax table for go."
- (or (eq char ?\n)
- (= (char-syntax char) ?\ )))
-
-(defun go-mode-backward-skip-comments ()
- "Skip backward over comments and whitespace."
- ;; only proceed if point is in a comment or white space
- (if (or (go-mode-in-comment)
- (go-mode-whitespace-p (char-after (point))))
- (let ((loop-guard t))
- (while (and
- loop-guard
- (not (bobp)))
-
- (cond ((go-mode-whitespace-p (char-after (point)))
- ;; moves point back over any whitespace
- (re-search-backward "[^[:space:]]"))
-
- ((go-mode-in-comment)
- ;; move point to char preceeding current comment
- (goto-char (1- (car (go-mode-in-comment)))))
-
- ;; not in a comment or whitespace? we must be done.
- (t (setq loop-guard nil)
- (forward-char 1)))))))
-
-(defun go-mode-indentation ()
- "Compute the ideal indentation level of the current line.
-
-To the first order, this is the brace depth of the current line,
-plus parens that follow certain keywords. case, default, and
-labels are outdented one level, and continuation lines are
-indented one level."
-
- (save-excursion
- (back-to-indentation)
- (let ((cs (go-mode-cs)))
- ;; Treat comments and strings differently only if the beginning
- ;; of the line is contained within them
- (when (and cs (= (point) (car cs)))
- (setq cs nil))
- ;; What type of context am I in?
(cond
- ((and cs (save-excursion
- (goto-char (car cs))
- (looking-at "`")))
- ;; Inside a multi-line string. Don't mess with indentation.
- nil)
- (cs
- ;; Inside a general comment
- (goto-char (car cs))
- (forward-char 1)
- (current-column))
+ ((go-in-string-p)
+ (current-indentation))
+ ((looking-at "[])}]")
+ (go-goto-opening-parenthesis (char-after))
+ (if (go-previous-line-has-dangling-op-p)
+ (- (current-indentation) tab-width)
+ (go--indentation-for-opening-parenthesis)))
+ ((progn (go--backward-irrelevant t) (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)))
+ ((zerop (go-paren-level))
+ 0)
+ ((progn (go-goto-opening-parenthesis) (< (go-paren-level) start-nesting))
+ (if (go-previous-line-has-dangling-op-p)
+ (current-indentation)
+ (+ (go--indentation-for-opening-parenthesis) tab-width)))
(t
- ;; Not in a multi-line string or comment
- (let ((indent 0)
- (inside-indenting-paren nil))
- ;; Count every enclosing brace, plus parens that follow
- ;; import, const, var, or type and indent according to
- ;; depth. This simple rule does quite well, but also has a
- ;; very large extent. It would be better if we could mimic
- ;; some nearby indentation.
- (save-excursion
- (skip-chars-forward "})")
- (let ((first t))
- (dolist (nest (go-mode-nesting))
- (case (char-after (car nest))
- ((?\{)
- (incf indent tab-width))
- ((?\()
- (goto-char (car nest))
- (go-mode-backward-skip-comments)
- (backward-char)
- ;; Really just want the token before
- (when (looking-back "\\<import\\|const\\|var\\|type\\|package"
- (max (- (point) 7) (point-min)))
- (incf indent tab-width)
- (when first
- (setq inside-indenting-paren t)))))
- (setq first nil))))
-
- ;; case, default, and labels are outdented 1 level
- (when (looking-at "\\<case\\>\\|\\<default\\>\\|\\w+\\s *:\\(\\S.\\|$\\)")
- (decf indent tab-width))
-
- (when (looking-at "\\w+\\s *:.+,\\s *$")
- (incf indent tab-width))
-
- ;; Continuation lines are indented 1 level
- (beginning-of-line) ; back up to end of previous line
- (backward-char)
- (go-mode-backward-skip-comments) ; back up past any comments
- (when (case (char-before)
- ((nil ?\{ ?:)
- ;; At the beginning of a block or the statement
- ;; following a label.
- nil)
- ((?\()
- ;; Usually a continuation line in an expression,
- ;; unless this paren is part of a factored
- ;; declaration.
- (not inside-indenting-paren))
- ((?,)
- ;; Could be inside a literal. We're a little
- ;; conservative here and consider any comma within
- ;; curly braces (as opposed to parens) to be a
- ;; literal separator. This will fail to recognize
- ;; line-breaks in parallel assignments as
- ;; continuation lines.
- (let ((depth (go-mode-nesting)))
- (and depth
- (not (eq (char-after (caar depth)) ?\{)))))
- (t
- ;; We're in the middle of a block. Did the
- ;; previous line end with an implicit or explicit
- ;; semicolon?
- (not (go-mode-semicolon-p))))
- (incf indent tab-width))
-
- (max indent 0)))))))
+ (current-indentation))))))
(defun go-mode-indent-line ()
- "Indent the current line according to `go-mode-indentation'."
(interactive)
+ (let (indent
+ shift-amt
+ end
+ (pos (- (point-max) (point)))
+ (point (point))
+ (beg (line-beginning-position)))
+ (back-to-indentation)
+ (if (go-in-string-or-comment-p)
+ (goto-char point)
+ (setq indent (go-indentation-at-point))
+ (if (looking-at (concat go-label-regexp ":\\([[:space:]]*/.+\\)?$\\|case .+:\\|default:"))
+ (decf indent tab-width))
+ (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))))))
- ;; turn off case folding to distinguish keywords from identifiers
- ;; e.g. "default" is a keyword; "Default" can be a variable name.
- (let ((case-fold-search nil))
- (let ((col (go-mode-indentation)))
- (when col
- (let ((offset (- (current-column) (current-indentation))))
- (indent-line-to col)
- (when (> offset 0)
- (forward-char offset)))))))
+(defun go-beginning-of-defun (&optional count)
+ (unless count (setq count 1))
+ (let ((first t) failure)
+ (dotimes (i (abs count))
+ (while (and (not failure)
+ (or first (go-in-string-or-comment-p)))
+ (if (>= count 0)
+ (progn
+ (go--backward-irrelevant)
+ (if (not (re-search-backward go-func-meth-regexp nil t))
+ (setq failure t)))
+ (if (looking-at go-func-meth-regexp)
+ (forward-char))
+ (if (not (re-search-forward go-func-meth-regexp nil t))
+ (setq failure t)))
+ (setq first nil)))
+ (if (< count 0)
+ (beginning-of-line))
+ (not failure)))
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Go mode
-;;
+(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 nil "Go"
+(define-derived-mode go-mode prog-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."
+This mode provides (not just) basic editing capabilities for
+working with Go code. It offers almost complete syntax
+highlighting, indentation that is almost identical to gofmt and
+proper parsing of the buffer content to allow features such as
+navigation by function, manipulation of comments or detection of
+strings.
+
+In addition to these core features, it offers various features to
+help with writing Go code. You can directly run buffer content
+through gofmt, read godoc documentation from within Emacs, modify
+and clean up the list of package imports or interact with the
+Playground (uploading and downloading pastes).
+
+The following extra functions are defined:
+
+- `gofmt'
+- `godoc'
+- `go-import-add'
+- `go-remove-unused-imports'
+- `go-goto-imports'
+- `go-play-buffer' and `go-play-region'
+- `go-download-play'
+- `godef-describe' and `godef-jump'
+
+If you want to automatically run `gofmt' before saving a file,
+add the following hook to your emacs configuration:
+
+\(add-hook 'before-save-hook 'gofmt-before-save)
+
+If you want to use `godef-jump' instead of etags (or similar),
+consider binding godef-jump to `M-.', which is the default key
+for `find-tag':
+
+\(add-hook 'go-mode-hook (lambda ()
+ (local-set-key (kbd \"M-.\") 'godef-jump)))
+
+Please note that godef is an external dependency. You can install
+it with
+
+go get code.google.com/p/rog-go/exp/cmd/godef
+
+
+If you're looking for even more integration with Go, namely
+on-the-fly syntax checking, auto-completion and snippets, it is
+recommended that you look at goflymake
+\(https://github.com/dougm/goflymake), gocode
+\(https://github.com/nsf/gocode) and yasnippet-go
+\(https://github.com/dominikh/yasnippet-go)"
;; Font lock
(set (make-local-variable 'font-lock-defaults)
- '(go-mode-font-lock-keywords nil nil nil nil))
-
- ;; Remove stale text properties
- (save-restriction
- (widen)
- (let ((modified (buffer-modified-p)))
- (remove-text-properties 1 (point-max)
- '(go-mode-cs nil go-mode-nesting nil))
- ;; remove-text-properties marks the buffer modified. undo that if it
- ;; wasn't originally marked modified.
- (set-buffer-modified-p modified)))
-
- ;; Reset the syntax mark caches
- (setq go-mode-mark-cs-end 1
- go-mode-mark-nesting-end 1)
- (add-hook 'before-change-functions #'go-mode-mark-clear-cache nil t)
- (add-hook 'after-change-functions #'go-mode-mark-clear-cs nil t)
+ '(go--build-font-lock-keywords))
;; Indentation
- (set (make-local-variable 'indent-line-function)
- #'go-mode-indent-line)
- (add-hook 'after-change-functions #'go-mode-delayed-electric-hook nil t)
+ (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)
+
+ (set (make-local-variable 'parse-sexp-lookup-properties) t)
+ (if (boundp 'syntax-propertize-function)
+ (set (make-local-variable 'syntax-propertize-function) 'go-propertize-syntax))
+
+ (set (make-local-variable 'go-dangling-cache) (make-hash-table :test 'eql))
+ (add-hook 'before-change-functions (lambda (x y) (setq go-dangling-cache (make-hash-table :test 'eql))) t t)
+
+
+ (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)
@@ -769,118 +496,116 @@
;; 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)))
+ (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))
+(add-to-list 'auto-mode-alist (cons "\\.go\\'" 'go-mode))
-(defun go-mode-reload ()
- "Reload go-mode.el and put the current buffer into Go mode.
-Useful for development work."
+(defun go--apply-rcs-patch (patch-buffer)
+ "Apply an RCS-formatted diff from PATCH-BUFFER to the current
+buffer."
+ (let ((target-buffer (current-buffer))
+ ;; Relative offset between buffer line numbers and line numbers
+ ;; in patch.
+ ;;
+ ;; Line numbers in the patch are based on the source file, so
+ ;; we have to keep an offset when making changes to the
+ ;; buffer.
+ ;;
+ ;; Appending lines decrements the offset (possibly making it
+ ;; negative), deleting lines increments it. This order
+ ;; simplifies the forward-line invocations.
+ (line-offset 0))
+ (save-excursion
+ (with-current-buffer patch-buffer
+ (goto-char (point-min))
+ (while (not (eobp))
+ (unless (looking-at "^\\([ad]\\)\\([0-9]+\\) \\([0-9]+\\)")
+ (error "invalid rcs patch or internal error in go--apply-rcs-patch"))
+ (forward-line)
+ (let ((action (match-string 1))
+ (from (string-to-number (match-string 2)))
+ (len (string-to-number (match-string 3))))
+ (cond
+ ((equal action "a")
+ (let ((start (point)))
+ (forward-line len)
+ (let ((text (buffer-substring start (point))))
+ (with-current-buffer target-buffer
+ (decf line-offset len)
+ (goto-char (point-min))
+ (forward-line (- from len line-offset))
+ (insert text)))))
+ ((equal action "d")
+ (with-current-buffer target-buffer
+ (goto-char (point-min))
+ (forward-line (- from line-offset 1))
+ (incf line-offset len)
+ (go--kill-whole-line len)))
+ (t
+ (error "invalid rcs patch or internal error in go--apply-rcs-patch")))))))))
+
+(defun gofmt ()
+ "Formats the current buffer according to the gofmt tool."
(interactive)
- (unload-feature 'go-mode)
- (require 'go-mode)
- (go-mode))
+ (let ((tmpfile (make-temp-file "gofmt" nil ".go"))
+ (patchbuf (get-buffer-create "*Gofmt patch*"))
+ (errbuf (get-buffer-create "*Gofmt Errors*"))
+ (coding-system-for-read 'utf-8)
+ (coding-system-for-write 'utf-8))
-;;;###autoload
-(defun gofmt ()
- "Pipe the current buffer through the external tool `gofmt`.
-Replace the current buffer on success; display errors on failure."
+ (with-current-buffer errbuf
+ (setq buffer-read-only nil)
+ (erase-buffer))
+ (with-current-buffer patchbuf
+ (erase-buffer))
- (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")))
- (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))
+ (write-region nil nil tmpfile)
- ;; gofmt failed: display the errors
- (gofmt-process-errors filename errbuf))))))
+ ;; We're using errbuf for the mixed stdout and stderr output. This
+ ;; is not an issue because gofmt -w does not produce any stdout
+ ;; output in case of success.
+ (if (zerop (call-process "gofmt" nil errbuf nil "-w" tmpfile))
+ (if (zerop (call-process-region (point-min) (point-max) "diff" nil patchbuf nil "-n" "-" tmpfile))
+ (progn
+ (kill-buffer errbuf)
+ (message "Buffer is already gofmted"))
+ (go--apply-rcs-patch patchbuf)
+ (kill-buffer errbuf)
+ (message "Applied gofmt"))
+ (message "Could not apply gofmt. Check errors for details")
+ (gofmt--process-errors (buffer-file-name) tmpfile errbuf))
- ;; Collapse any window opened on outbuf if shell-command-on-region
- ;; displayed it.
- (delete-windows-on patchbuf)))
- (kill-buffer patchbuf))))
+ (kill-buffer patchbuf)
+ (delete-file tmpfile)))
-(defun gofmt-replace-buffer (srcbuf patchbuf)
- (with-current-buffer srcbuf
- (erase-buffer)
- (insert-buffer-substring patchbuf)))
-(defconst gofmt-stdin-tag "<standard input>")
-
-(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)
+(defun gofmt--process-errors (filename tmpfile 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)))
+ (while (search-forward-regexp (concat "^\\(" (regexp-quote tmpfile) "\\):") nil t)
+ (replace-match (file-name-nondirectory filename) t t nil 1))
+ (compilation-mode)
+ (display-buffer errbuf)))
;;;###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)"
+ (add-hook 'before-save-hook 'gofmt-before-save).
+
+Note that this will cause go-mode to get loaded the first time
+you save any file, kind of defeating the point of autoloading."
(interactive)
(when (eq major-mode 'go-mode) (gofmt)))
-(defun godoc-read-query ()
+(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
@@ -889,12 +614,12 @@
(symbol (if bounds
(buffer-substring-no-properties (car bounds)
(cdr bounds)))))
- (read-string (if symbol
- (format "godoc (default %s): " symbol)
- "godoc: ")
- nil nil symbol)))
+ (completing-read (if symbol
+ (format "godoc (default %s): " symbol)
+ "godoc: ")
+ (go--old-completion-list-style (go-packages)) nil nil nil 'go-godoc-history symbol)))
-(defun godoc-get-buffer (query)
+(defun godoc--get-buffer (query)
"Get an empty buffer for a godoc query."
(let* ((buffer-name (concat "*godoc " query "*"))
(buffer (get-buffer buffer-name)))
@@ -902,13 +627,14 @@
(when buffer (kill-buffer buffer))
(get-buffer-create buffer-name)))
-(defun godoc-buffer-sentinel (proc event)
+(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))
- (display-buffer (current-buffer) 'not-this-window))
- ((not (= (process-exit-status proc) 0)) ;; Error exit.
+ (view-mode 1)
+ (display-buffer (current-buffer) t))
+ ((/= (process-exit-status proc) 0) ;; Error exit.
(let ((output (buffer-string)))
(kill-buffer (current-buffer))
(message (concat "godoc: " output)))))))
@@ -916,12 +642,294 @@
;;;###autoload
(defun godoc (query)
"Show go documentation for a query, much like M-x man."
- (interactive (list (godoc-read-query)))
+ (interactive (list (godoc--read-query)))
(unless (string= query "")
(set-process-sentinel
- (start-process-shell-command "godoc" (godoc-get-buffer query)
+ (start-process-shell-command "godoc" (godoc--get-buffer query)
(concat "godoc " query))
- 'godoc-buffer-sentinel)
+ 'godoc--buffer-sentinel)
nil))
+(defun go-goto-imports ()
+ "Move point to the block of imports.
+
+If using
+
+ import (
+ \"foo\"
+ \"bar\"
+ )
+
+it will move point directly behind the last import.
+
+If using
+
+ import \"foo\"
+ import \"bar\"
+
+it will move point to the next line after the last import.
+
+If no imports can be found, point will be moved after the package
+declaration."
+ (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)
+ 'block)
+ ((re-search-forward "\\(^import \\([^\"]+ \\)?\"[^\"]+\"\n?\\)+" nil t)
+ 'single)
+ ((re-search-forward "^[[:space:]\n]*package .+?\n" nil t)
+ (message "No imports found, moving point after package declaration")
+ 'none)
+ (t
+ (goto-char old-point)
+ (message "No imports or package declaration found. Is this really a Go file?")
+ 'fail))))
+
+(defun go-play-buffer ()
+ "Like `go-play-region', but acts on the entire buffer."
+ (interactive)
+ (go-play-region (point-min) (point-max)))
+
+(defun go-play-region (start end)
+ "Send the region to the Playground and stores the resulting
+link in the kill ring."
+ (interactive "r")
+ (let* ((url-request-method "POST")
+ (url-request-extra-headers
+ '(("Content-Type" . "application/x-www-form-urlencoded")))
+ (url-request-data (buffer-substring-no-properties start end))
+ (content-buf (url-retrieve
+ "http://play.golang.org/share"
+ (lambda (arg)
+ (cond
+ ((equal :error (car arg))
+ (signal 'go-play-error (cdr arg)))
+ (t
+ (re-search-forward "\n\n")
+ (kill-new (format "http://play.golang.org/p/%s" (buffer-substring (point) (point-max))))
+ (message "http://play.golang.org/p/%s" (buffer-substring (point) (point-max)))))))))))
+
+;;;###autoload
+(defun go-download-play (url)
+ "Downloads a paste from the playground and inserts it in a Go
+buffer. Tries to look for a URL at point."
+ (interactive (list (read-from-minibuffer "Playground URL: " (ffap-url-p (ffap-string-at-point 'url)))))
+ (with-current-buffer
+ (let ((url-request-method "GET") url-request-data url-request-extra-headers)
+ (url-retrieve-synchronously (concat url ".go")))
+ (let ((buffer (generate-new-buffer (concat (car (last (split-string url "/"))) ".go"))))
+ (goto-char (point-min))
+ (re-search-forward "\n\n")
+ (copy-to-buffer buffer (point) (point-max))
+ (kill-buffer)
+ (with-current-buffer buffer
+ (go-mode)
+ (switch-to-buffer buffer)))))
+
+(defun go-propertize-syntax (start end)
+ (save-excursion
+ (goto-char start)
+ (while (search-forward "\\" end t)
+ (put-text-property (1- (point)) (point) 'syntax-table (if (= (char-after) ?`) '(1) '(9))))))
+
+;; ;; Commented until we actually make use of this function
+;; (defun go--common-prefix (sequences)
+;; ;; mismatch and reduce are cl
+;; (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)))
+
+(defun go-import-add (arg import)
+ "Add a new import to the list of imports.
+
+When called with a prefix argument asks for an alternative name
+to import the package as.
+
+If no list exists yet, one will be created if possible.
+
+If an identical import has been commented, it will be
+uncommented, otherwise a new import will be added."
+
+ ;; - If there's a matching `// import "foo"`, uncomment it
+ ;; - If we're in an import() block and there's a matching `"foo"`, uncomment it
+ ;; - Otherwise add a new import, with the appropriate syntax
+ (interactive
+ (list
+ current-prefix-arg
+ (replace-regexp-in-string "^[\"']\\|[\"']$" "" (completing-read "Package: " (go--old-completion-list-style (go-packages))))))
+ (save-excursion
+ (let (as line import-start)
+ (if arg
+ (setq as (read-from-minibuffer "Import as: ")))
+ (if as
+ (setq line (format "%s \"%s\"" as import))
+ (setq line (format "\"%s\"" import)))
+
+ (goto-char (point-min))
+ (if (re-search-forward (concat "^[[:space:]]*//[[:space:]]*import " line "$") nil t)
+ (uncomment-region (line-beginning-position) (line-end-position))
+ (case (go-goto-imports)
+ ('fail (message "Could not find a place to add import."))
+ ('block
+ (save-excursion
+ (re-search-backward "^import (")
+ (setq import-start (point)))
+ (if (re-search-backward (concat "^[[:space:]]*//[[:space:]]*" line "$") import-start t)
+ (uncomment-region (line-beginning-position) (line-end-position))
+ (insert "\n\t" line)))
+ ('single (insert "import " line "\n"))
+ ('none (insert "\nimport (\n\t" line "\n)\n")))))))
+
+(defun go-root-and-paths ()
+ (let* ((output (split-string (shell-command-to-string "go env GOROOT GOPATH") "\n"))
+ (root (car output))
+ (paths (split-string (cadr output) ":")))
+ (append (list root) paths)))
+
+(defun go--string-prefix-p (s1 s2 &optional ignore-case)
+ "Return non-nil if S1 is a prefix of S2.
+If IGNORE-CASE is non-nil, the comparison is case-insensitive."
+ (eq t (compare-strings s1 nil nil
+ s2 0 (length s1) ignore-case)))
+
+(defun go--directory-dirs (dir)
+ "Recursively return all subdirectories in DIR."
+ (if (file-directory-p dir)
+ (let ((dir (directory-file-name dir))
+ (dirs '())
+ (files (directory-files dir nil nil t)))
+ (dolist (file files)
+ (unless (member file '("." ".."))
+ (let ((file (concat dir "/" file)))
+ (if (file-directory-p file)
+ (setq dirs (append (cons file
+ (go--directory-dirs file))
+ dirs))))))
+ dirs)
+ '()))
+
+
+(defun go-packages ()
+ (sort
+ (delete-dups
+ (mapcan
+ (lambda (topdir)
+ (let ((pkgdir (concat topdir "/pkg/")))
+ (mapcan (lambda (dir)
+ (mapcar (lambda (file)
+ (let ((sub (substring file (length pkgdir) -2)))
+ (unless (or (go--string-prefix-p "obj/" sub) (go--string-prefix-p "tool/" sub))
+ (mapconcat 'identity (cdr (split-string sub "/")) "/"))))
+ (if (file-directory-p dir)
+ (directory-files dir t "\\.a$"))))
+ (if (file-directory-p pkgdir)
+ (go--directory-dirs pkgdir)))))
+ (go-root-and-paths)))
+ 'string<))
+
+(defun go-unused-imports-lines ()
+ ;; FIXME Technically, -o /dev/null fails in quite some cases (on
+ ;; Windows, when compiling from within GOPATH). Practically,
+ ;; however, it has the same end result: There won't be a
+ ;; compiled binary/archive, and we'll get our import errors when
+ ;; there are any.
+ (reverse (remove nil
+ (mapcar
+ (lambda (line)
+ (if (string-match "^\\(.+\\):\\([[:digit:]]+\\): imported and not used: \".+\"$" line)
+ (if (string= (file-truename (match-string 1 line)) (file-truename buffer-file-name))
+ (string-to-number (match-string 2 line)))))
+ (split-string (shell-command-to-string
+ (if (string-match "_test\.go$" buffer-file-truename)
+ "go test -c"
+ "go build -o /dev/null")) "\n")))))
+
+(defun go-remove-unused-imports (arg)
+ "Removes all unused imports. If ARG is non-nil, unused imports
+will be commented, otherwise they will be removed completely."
+ (interactive "P")
+ (save-excursion
+ (let ((cur-buffer (current-buffer)) flymake-state lines)
+ (when (boundp 'flymake-mode)
+ (setq flymake-state flymake-mode)
+ (flymake-mode-off))
+ (save-some-buffers nil (lambda () (equal cur-buffer (current-buffer))))
+ (if (buffer-modified-p)
+ (message "Cannot operate on unsaved buffer")
+ (setq lines (go-unused-imports-lines))
+ (dolist (import lines)
+ (goto-char (point-min))
+ (forward-line (1- import))
+ (beginning-of-line)
+ (if arg
+ (comment-region (line-beginning-position) (line-end-position))
+ (go--kill-whole-line)))
+ (message "Removed %d imports" (length lines)))
+ (if flymake-state (flymake-mode-on)))))
+
+(defun godef--find-file-line-column (specifier)
+ "Given a file name in the format of `filename:line:column',
+visit FILENAME and go to line LINE and column COLUMN."
+ (let* ((components (split-string specifier ":"))
+ (line (string-to-number (nth 1 components)))
+ (column (string-to-number (nth 2 components))))
+ (with-current-buffer (find-file (car components))
+ (goto-char (point-min))
+ (forward-line (1- line))
+ (beginning-of-line)
+ (forward-char (1- column))
+ (if (buffer-modified-p)
+ (message "Buffer is modified, file position might not have been correct")))))
+
+(defun godef--call (point)
+ "Call godef, acquiring definition position and expression
+description at POINT."
+ (if (go--xemacs-p)
+ (message "godef does not reliably work in XEmacs, expect bad results"))
+ (if (not buffer-file-name)
+ (message "Cannot use godef on a buffer without a file name")
+ (let ((outbuf (get-buffer-create "*godef*")))
+ (with-current-buffer outbuf
+ (erase-buffer))
+ (call-process-region (point-min) (point-max) "godef" nil outbuf nil "-i" "-t" "-f" (file-truename buffer-file-name) "-o" (number-to-string (go--position-bytes (point))))
+ (with-current-buffer outbuf
+ (split-string (buffer-substring-no-properties (point-min) (point-max)) "\n")))))
+
+(defun godef-describe (point)
+ "Describe the expression at POINT."
+ (interactive "d")
+ (condition-case nil
+ (let ((description (nth 1 (godef--call point))))
+ (if (string= "" description)
+ (message "No description found for expression at point")
+ (message "%s" description)))
+ (file-error (message "Could not run godef binary"))))
+
+(defun godef-jump (point)
+ "Jump to the definition of the expression at POINT."
+ (interactive "d")
+ (condition-case nil
+ (let ((file (car (godef--call point))))
+ (cond
+ ((string= "-" file)
+ (message "godef: expression is not defined anywhere"))
+ ((string= "godef: no identifier found" file)
+ (message "%s" file))
+ ((go--string-prefix-p "godef: no declaration found for " file)
+ (message "%s" file))
+ (t
+ (push-mark)
+ (godef--find-file-line-column file))))
+ (file-error (message "Could not run godef binary"))))
+
(provide 'go-mode)
Repository URL: https://bitbucket.org/xemacs/prog-modes/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
_______________________________________________
XEmacs-Patches mailing list
XEmacs-Patches(a)xemacs.org
http://lists.xemacs.org/mailman/listinfo/xemacs-patches
1 new commit in xemacs-21.4:
https://bitbucket.org/xemacs/xemacs-21.4/commits/13d13fa19748/
Changeset: 13d13fa19748
User: Vin Shelton
Date: 2013-04-12 17:34:28
Summary: Apply Sean MacLennon's patch to recognize shifted function keys directly.
Affected #: 2 files
diff -r 2ccd146e07e9e2554f1e759d1fddee2b5d6527d8 -r 13d13fa1974802424c254ff5e981d148f8163dcd src/ChangeLog
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,9 @@
+2013-04-12 Vin Shelton <acs(a)xemacs.org>
+
+ * event-Xt.c (x_event_to_emacs_event): Allow XEmacs to recognize
+ shifted function keys directly. This is likely an XFree bug.
+ Patch by Sean MacLennan.
+
2012-07-12 Vin Shelton <acs(a)xemacs.org>
* glyphs-eimage.c: Fix this so it compiles with libpng-1.5.10.
diff -r 2ccd146e07e9e2554f1e759d1fddee2b5d6527d8 -r 13d13fa1974802424c254ff5e981d148f8163dcd src/event-Xt.c
--- a/src/event-Xt.c
+++ b/src/event-Xt.c
@@ -1260,7 +1260,25 @@
KeySym bot = XLookupKeysym (ev, Mode_switch_p ? 2 : 0);
KeySym top = XLookupKeysym (ev, Mode_switch_p ? 3 : 1);
if (top && bot && top != bot)
- modifiers &= ~XEMACS_MOD_SHIFT;
+ /* Look directly for shifted function keycodes */
+ switch(top) {
+ case 0x1008fe01:
+ case 0x1008fe02:
+ case 0x1008fe03:
+ case 0x1008fe04:
+ case 0x1008fe05:
+ case 0x1008fe06:
+ case 0x1008fe07:
+ case 0x1008fe08:
+ case 0x1008fe09:
+ case 0x1008fe0a:
+ case 0x1008fe0b:
+ case 0x1008fe0c:
+ break;
+ default:
+ modifiers &= ~XEMACS_MOD_SHIFT;
+ break;
+ }
}
emacs_event->event_type = key_press_event;
emacs_event->timestamp = ev->time;
Repository URL: https://bitbucket.org/xemacs/xemacs-21.4/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
_______________________________________________
XEmacs-Patches mailing list
XEmacs-Patches(a)xemacs.org
http://lists.xemacs.org/mailman/listinfo/xemacs-patches
Hi,
Below is a patch that adds ID-FORMAT to file-attributes. It is posted
here for getting views on it (I'm not normally in this part of the
code).
Standard ChangeLogs items are missing and will be added.
Windows support is missing but should be possible to add by
implementing the proper qxe_getgrgid function. (Which I don't indent
to do without having the possibility to test it.)
Apart from that I wonder about the code that does call2 and call3 in
the "if (!NILP (handler))"-part. What is the !NILP (handler)-stuff?
and is the call2 and call3 appropriate? The later is taken verbatim
from GNU that has the same construction. (But it feel bad not knowing
a thing about what is going on ;-)
Your // Mats
----------------------------------------------------------------------
diff -r ec3712ffd0e6 src/dired.c
--- a/src/dired.c Fri Mar 15 13:52:53 2013 -0600
+++ b/src/dired.c Sun Mar 31 14:41:30 2013 +0200
@@ -820,14 +820,21 @@
}
#endif
-DEFUN ("file-attributes", Ffile_attributes, 1, 1, 0, /*
+DEFUN ("file-attributes", Ffile_attributes, 1, 2, 0, /*
Return a list of attributes of file FILENAME.
Value is nil if specified file cannot be opened.
+
+ID-FORMAT specifies the preferred format of attributes uid and gid (see
+below) - valid values are 'string and 'integer. The latter is the
+default, but we plan to change that, so you should specify a non-nil value
+for ID-FORMAT if you use the returned uid or gid.
+
Otherwise, list elements are:
0. t for directory, string (name linked to) for symbolic link, or nil.
1. Number of links to file.
- 2. File uid.
- 3. File gid.
+ 2. File uid as a string or a number. If a string value cannot be
+ looked up, a numeric value, either an integer or a float, is returned.
+ 3. File gid, likewise.
4. Last access time, as a list of two integers.
First integer has high-order 16 bits of time, second has low 16 bits.
5. Last modification time, likewise.
@@ -840,7 +847,7 @@
If file does not exist, returns nil.
*/
- (filename))
+ (filename, id_format))
{
/* This function can GC. GC checked 1997.06.04. */
Lisp_Object directory = Qnil;
@@ -849,6 +856,9 @@
Lisp_Object handler, mode, modestring = Qnil, size, gid;
struct gcpro gcpro1, gcpro2, gcpro3;
+ Lisp_Object uidInfo = Qnil;
+ Lisp_Object gidInfo = Qnil;
+
GCPRO3 (filename, directory, modestring);
filename = Fexpand_file_name (filename, Qnil);
@@ -858,7 +868,10 @@
if (!NILP (handler))
{
UNGCPRO;
- return call2 (handler, Qfile_attributes, filename);
+ if (NILP(id_format))
+ return call2 (handler, Qfile_attributes, filename);
+ else
+ return call3 (handler, Qfile_attributes, filename, id_format);
}
if (qxe_lstat (XSTRING_DATA (filename), &s) < 0)
@@ -925,11 +938,25 @@
gid = (s.st_gid != getegid ()) ? Qt : Qnil;
#endif /* BSD4_2 or BSD4_3 */
+ if (NILP(id_format) || EQ (id_format, Qinteger))
+ {
+ uidInfo = make_integer (s.st_uid);
+ gidInfo = make_integer (s.st_gid);
+ }
+ else
+ {
+ struct passwd *pw = qxe_getpwuid (s.st_uid);
+ struct group *gr = qxe_getgrgid (s.st_gid);
+
+ uidInfo = build_istring (pw ? (Ibyte *) pw->pw_name : NULL);
+ gidInfo = build_istring (gr ? (Ibyte *) gr->gr_name : NULL);
+ }
+
RETURN_UNGCPRO (listn (12,
mode,
make_integer (s.st_nlink),
- make_integer (s.st_uid),
- make_integer (s.st_gid),
+ uidInfo,
+ gidInfo,
make_time (s.st_atime),
make_time (s.st_mtime),
make_time (s.st_ctime),
diff -r ec3712ffd0e6 src/sysdep.c
--- a/src/sysdep.c Fri Mar 15 13:52:53 2013 -0600
+++ b/src/sysdep.c Sun Mar 31 14:41:30 2013 +0200
@@ -3127,6 +3127,13 @@
#endif /* WIN32_NATIVE */
}
+// TODO: WIN32 mapping
+struct group *
+qxe_getgrgid (gid_t gid)
+{
+ return getgrgid (gid);
+}
+
#ifndef WIN32_NATIVE
struct passwd *
diff -r ec3712ffd0e6 src/syspwd.h
--- a/src/syspwd.h Fri Mar 15 13:52:53 2013 -0600
+++ b/src/syspwd.h Sun Mar 31 14:41:30 2013 +0200
@@ -20,6 +20,7 @@
#ifndef WIN32_NATIVE
# include <pwd.h>
+# include <grp.h>
#else /* WIN32_NATIVE */
@@ -52,6 +53,7 @@
struct passwd *qxe_getpwnam (const Ibyte *name);
struct passwd *qxe_getpwuid (uid_t uid);
+struct group *qxe_getgrgid (gid_t gid);
struct passwd *qxe_getpwent (void);
#endif /* emacs */
diff -r ec3712ffd0e6 tests/automated/dired-tests.el
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/automated/dired-tests.el Sun Mar 31 14:41:30 2013 +0200
@@ -0,0 +1,53 @@
+;; Copyright (C) 2013 Free Software Foundation, Inc.
+
+;; Author: Mats Lidell <matsl(a)xemacs.org>
+;; Maintainer:
+;; Created: 2013
+;; Keywords: tests
+
+;; This file is part of XEmacs.
+
+;; XEmacs is free software: you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by the
+;; Free Software Foundation, either version 3 of the License, or (at your
+;; option) any later version.
+
+;; XEmacs is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+;; for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with XEmacs. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Synched up with: Not in FSF.
+
+;;; Commentary:
+
+;; Test tag support.
+;; See test-harness.el for instructions on how to run these tests.
+
+(require 'test-harness)
+
+(let* ((test-file-name (make-temp-file "dired-test"))
+ (attr (file-attributes test-file-name)))
+ (Assert (equal (nth 0 attr) nil))
+ (Assert (equal (nth 1 attr) 1))
+ (Assert (numberp (nth 2 attr)))
+ (Assert (equal (nth 2 attr) (user-uid)))
+ (Assert (numberp (nth 3 attr)))
+ (Assert (equal (nth 4 attr) (nth 5 attr)))
+ (Assert (equal (nth 4 attr) (nth 6 attr)))
+ (Assert (equal (nth 7 attr) 0)))
+
+;; Optional ID-FORMAT set -> uid and gid are strings
+(let* ((test-file-name (make-temp-file "dired-test"))
+ (attr (file-attributes test-file-name t)))
+ (Assert (equal (nth 0 attr) nil))
+ (Assert (equal (nth 1 attr) 1))
+ (Assert (stringp (nth 2 attr)))
+ (Assert (equal (nth 2 attr) (user-login-name)))
+ (Assert (stringp (nth 3 attr)))
+ (Assert (equal (nth 4 attr) (nth 5 attr)))
+ (Assert (equal (nth 4 attr) (nth 6 attr)))
+ (Assert (equal (nth 7 attr) 0)))
----------------------------------------------------------------------
_______________________________________________
XEmacs-Patches mailing list
XEmacs-Patches(a)xemacs.org
http://lists.xemacs.org/mailman/listinfo/xemacs-patches