commit 8663fad0a70e60e130ae4cd0529ead66fbad2250 (HEAD, refs/remotes/origin/master) Author: Sam Steingold Date: Mon Nov 14 23:37:33 2016 -0500 add `vc-git-print-log-follow' and use it in `vc-git-print-log' When `vc-git-print-log-follow' is true and all files are non-directory, pass "--follow" to "git log". This works around bug#8756 and bug#16422. diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el index 6d451be..9df581d 100644 --- a/lisp/vc/vc-git.el +++ b/lisp/vc/vc-git.el @@ -886,6 +886,11 @@ This prompts for a branch to merge from." (autoload 'vc-setup-buffer "vc-dispatcher") +(defcustom vc-git-print-log-follow nil + "If true, follow renames in Git logs for files." + :type 'boolean + :version "26.1") + (defun vc-git-print-log (files buffer &optional shortlog start-revision limit) "Print commit log associated with FILES into specified BUFFER. If SHORTLOG is non-nil, use a short format based on `vc-git-root-log-format'. @@ -905,7 +910,13 @@ If LIMIT is non-nil, show no more than this many entries." (apply 'vc-git-command buffer 'async files (append - '("log" "--no-color" "--follow") + '("log" "--no-color") + (when (and vc-git-print-log-follow + (not (cl-some #'file-directory-p files))) + ;; "--follow" on directories is broken + ;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=8756 + ;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=16422 + (list "--follow")) (when shortlog `("--graph" "--decorate" "--date=short" ,(format "--pretty=tformat:%s" commit 1f97c37bc6fb8cfd60731cef8df0aebdd509f23d Author: Sam Steingold Date: Mon Nov 14 19:13:20 2016 -0500 `toggle-truncate-lines' obsoletes `gnus-summary-toggle-truncation' diff --git a/lisp/gnus/gnus-sum.el b/lisp/gnus/gnus-sum.el index 910c796..b6023c2 100644 --- a/lisp/gnus/gnus-sum.el +++ b/lisp/gnus/gnus-sum.el @@ -1888,7 +1888,7 @@ increase the score of each group you read." "&" gnus-summary-execute-command "c" gnus-summary-catchup-and-exit "\C-w" gnus-summary-mark-region-as-read - "\C-t" gnus-summary-toggle-truncation + "\C-t" toggle-truncate-lines "?" gnus-summary-mark-as-dormant "\C-c\M-\C-s" gnus-summary-limit-include-expunged "\C-c\C-s\C-n" gnus-summary-sort-by-number @@ -2768,7 +2768,7 @@ gnus-summary-show-article-from-menu-as-charset-%s" cs)))) ["Run command on articles..." gnus-summary-universal-argument t] ["Search articles forward..." gnus-summary-search-article-forward t] ["Search articles backward..." gnus-summary-search-article-backward t] - ["Toggle line truncation" gnus-summary-toggle-truncation t] + ["Toggle line truncation" toggle-truncate-lines t] ["Expand window" gnus-summary-expand-window t] ["Expire expirable articles" gnus-summary-expire-articles (gnus-check-backend-function @@ -7059,14 +7059,8 @@ buffer." (gnus-summary-remove-process-mark article))))) (gnus-summary-position-point)) -(defun gnus-summary-toggle-truncation (&optional arg) - "Toggle truncation of summary lines. -With ARG, turn line truncation on if ARG is positive." - (interactive "P") - (setq truncate-lines - (if (null arg) (not truncate-lines) - (> (prefix-numeric-value arg) 0))) - (redraw-display)) +(define-obsolete-function-alias + 'gnus-summary-toggle-truncation 'toggle-truncate-lines "26.1") (defun gnus-summary-find-for-reselect () "Return the number of an article to stay on across a reselect. commit 39f0543ca18142f318a1c90f100632c49a000a1c Author: Sam Steingold Date: Mon Nov 14 19:08:54 2016 -0500 vc-git-print-log: pass "--follow" to "log" to handle renamed files diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el index 43a831f..6d451be 100644 --- a/lisp/vc/vc-git.el +++ b/lisp/vc/vc-git.el @@ -905,7 +905,7 @@ If LIMIT is non-nil, show no more than this many entries." (apply 'vc-git-command buffer 'async files (append - '("log" "--no-color") + '("log" "--no-color" "--follow") (when shortlog `("--graph" "--decorate" "--date=short" ,(format "--pretty=tformat:%s" commit 4b8703097225c85d90d80f7704371f490a559da1 Author: Eli Zaretskii Date: Mon Nov 14 21:25:44 2016 +0200 Revert "Improve case-insensitive checks (Bug#24441)" This reverts commit 2f5e0b1bf7b0ac4f450847db34d599a072020600. I see no reason for removing code, documentation, and comments in the original commit. diff --git a/doc/lispref/files.texi b/doc/lispref/files.texi index ab0dcae..70c7177 100644 --- a/doc/lispref/files.texi +++ b/doc/lispref/files.texi @@ -1144,9 +1144,17 @@ return value is unspecified. Sometimes file names or their parts need to be compared as strings, in which case it's important to know whether the underlying filesystem is case-insensitive. This function returns @code{t} if file -@var{filename} is on a case-insensitive filesystem. On platforms where -this information is not available, this function guesses based on -common practice. +@var{filename} is on a case-insensitive filesystem. It always returns +@code{t} on MS-DOS and MS-Windows. On Cygwin and Mac OS X, +filesystems may or may not be case-insensitive, and the function tries +to determine case-sensitivity by a runtime test. If the test is +inconclusive, the function returns @code{t} on Cygwin and @code{nil} +on Mac OS X. + +Currently this function always returns @code{nil} on platforms other +than MS-DOS, MS-Windows, Cygwin, and Mac OS X. It does not detect +case-insensitivity of mounted filesystems, such as Samba shares or +NFS-mounted Windows volumes. @end defun @defun file-in-directory-p file dir diff --git a/src/fileio.c b/src/fileio.c index eec3591..f3f8f42 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -2236,10 +2236,13 @@ internal_delete_file (Lisp_Object filename) return NILP (tem); } -/* Return true if FILENAME is on a case-insensitive file system. - Use a runtime test if available. Otherwise, assume the file system - is case-insensitive on Microsoft-based platforms and case-sensitive - elsewhere. +/* Filesystems are case-sensitive on all supported systems except + MS-Windows, MS-DOS, Cygwin, and Mac OS X. They are always + case-insensitive on the first two, but they may or may not be + case-insensitive on Cygwin and OS X. The following function + attempts to provide a runtime test on those two systems. If the + test is not conclusive, we assume case-insensitivity on Cygwin and + case-sensitivity on Mac OS X. FIXME: Mounted filesystems on Posix hosts, like Samba shares or NFS-mounted Windows volumes, might be case-insensitive. Can we @@ -2248,65 +2251,33 @@ internal_delete_file (Lisp_Object filename) static bool file_name_case_insensitive_p (const char *filename) { -#ifdef _PC_CASE_INSENSITIVE +#ifdef DOS_NT + return 1; +#elif defined CYGWIN +/* As of Cygwin-2.6.1, pathconf supports _PC_CASE_INSENSITIVE. */ +# ifdef _PC_CASE_INSENSITIVE int res = pathconf (filename, _PC_CASE_INSENSITIVE); - if (0 < res) - return true; - if (res == 0 || errno != EINVAL) - return false; -#elif defined _PC_CASE_SENSITIVE - int res = pathconf (filename, _PC_CASE_SENSITIVE); - if (res == 0) - return true; - if (0 < res || errno != EINVAL) - return false; -#endif - -#ifdef DARWIN_OS - /* It is not clear whether this section is needed. For now, rely on - pathconf and skip this section. If pathconf does not work, - please recompile Emacs with -DDARWIN_OS_CASE_SENSITIVE_FIXME=1 or - -DDARWIN_OS_CASE_SENSITIVE_FIXME=2, and file a bug report saying - whether this fixed your problem. */ -# ifndef DARWIN_OS_CASE_SENSITIVE_FIXME - int DARWIN_OS_CASE_SENSITIVE_FIXME = 0; + if (res < 0) + return 1; + return res > 0; +# else + return 1; # endif - - if (DARWIN_OS_CASE_SENSITIVE_FIXME == 1) - { - /* This is based on developer.apple.com's getattrlist man page. */ - struct attrlist alist = {.volattr = ATTR_VOL_CAPABILITIES}; - struct vol_capabilities_attr_t vcaps; - if (getattrlist (filename, &alist, &vcaps, sizeof vcaps, 0) == 0) - { - if (vcaps.valid[VOL_CAPABILITIES_FORMAT] & VOL_CAP_FMT_CASE_SENSITIVE) - return ! (vcaps.capabilities[VOL_CAPABILITIES_FORMAT] - & VOL_CAP_FMT_CASE_SENSITIVE); - } - else if (errno != EINVAL) - return false; - } - else if (DARWIN_OS_CASE_SENSITIVE_FIXME == 2) - { - /* The following is based on - http://lists.apple.com/archives/darwin-dev/2007/Apr/msg00010.html. */ - struct attrlist alist; - unsigned char buffer[sizeof (vol_capabilities_attr_t) + sizeof (size_t)]; - - memset (&alist, 0, sizeof (alist)); - alist.volattr = ATTR_VOL_CAPABILITIES; - if (getattrlist (filename, &alist, buffer, sizeof (buffer), 0) - || !(alist.volattr & ATTR_VOL_CAPABILITIES)) - return 0; - vol_capabilities_attr_t *vcaps = buffer; - return !(vcaps->capabilities[0] & VOL_CAP_FMT_CASE_SENSITIVE); - } -#endif - -#if defined CYGWIN || defined DOS_NT - return true; +#elif defined DARWIN_OS + /* The following is based on + http://lists.apple.com/archives/darwin-dev/2007/Apr/msg00010.html. */ + struct attrlist alist; + unsigned char buffer[sizeof (vol_capabilities_attr_t) + sizeof (size_t)]; + + memset (&alist, 0, sizeof (alist)); + alist.volattr = ATTR_VOL_CAPABILITIES; + if (getattrlist (filename, &alist, buffer, sizeof (buffer), 0) + || !(alist.volattr & ATTR_VOL_CAPABILITIES)) + return 0; + vol_capabilities_attr_t *vcaps = buffer; + return !(vcaps->capabilities[0] & VOL_CAP_FMT_CASE_SENSITIVE); #else - return false; + return 0; #endif } @@ -2378,7 +2349,7 @@ This is what happens in interactive use with M-x. */) /* If the filesystem is case-insensitive and the file names are identical but for the case, don't ask for confirmation: they simply want to change the letter-case of the file name. */ - if ((! file_name_case_insensitive_p (SSDATA (encoded_file)) + if ((!(file_name_case_insensitive_p (SSDATA (encoded_file))) || NILP (Fstring_equal (Fdowncase (file), Fdowncase (newname)))) && ((NILP (ok_if_already_exists) || INTEGERP (ok_if_already_exists)))) barf_or_query_if_file_exists (newname, false, "rename to it", commit eda171a924a888db9b705ba7146fcdc13d9a84d3 Author: Wilson Snyder Date: Mon Nov 14 13:47:31 2016 -0500 Update verilog-mode.el * verilog-mode.el (verilog-read-decls, verilog-calc-1): Fix "default clocking" indentation and preventing AUTOs from working, bug1084. Reported by Alan Morgan. (verilog-diff-report): Fix `verilog-diff-report' not returning bad status on differences, bug1087. Reported by Eric Jackowski. (verilog-auto-inst-param-value) (verilog-auto-inst-param-value-type, verilog-read-sub-decls) (verilog-read-sub-decls-expr, verilog-read-sub-decls-gate) (verilog-read-sub-decls-line, verilog-read-sub-decls-sig) (verilog-read-sub-decls-type): When `verilog-auto-inst-param-value-type' is set, which is now the default, AUTOINPUT etc will now substitute parameter types from submodules, bug1061. Reported by Brad Dobbie. (verilog-auto-reset, verilog-backward-case-item) (verilog-extended-case-re, verilog-read-always-signals-recurse): Fix indentation of randcase, bug1072. Reported by David Rogoff. (verilog-read-sub-decls-expr) (verilog-sig-multidim-string): Fix AUTOINST ordering of dimensions in generated comments, bug1057. Reported by Kaushal Modi. (verilog-auto-wire-comment, verilog-insert-definition): Add `verilog-auto-wire-comment' to suppress wire comments. Reported by Eric Jackowski. (verilog-extended-complete-re): Fix indentation of class static functions, bug1053. Reported by Gregory Czajkowski. (verilog-module-filenames): Support tramp for finding verilog modules. Reported by Nevada Sanchez. diff --git a/lisp/progmodes/verilog-mode.el b/lisp/progmodes/verilog-mode.el index fd2e96a..5f07cbb 100644 --- a/lisp/progmodes/verilog-mode.el +++ b/lisp/progmodes/verilog-mode.el @@ -123,7 +123,7 @@ ;; ;; This variable will always hold the version number of the mode -(defconst verilog-mode-version "2016-03-22-7547e76-vpo-GNU" +(defconst verilog-mode-version "2016-11-14-26d3540-vpo-GNU" "Version of this Verilog mode.") (defconst verilog-mode-release-emacs t "If non-nil, this version of Verilog mode was released with Emacs itself.") @@ -753,6 +753,13 @@ mode is experimental." :type 'boolean) (put 'verilog-auto-declare-nettype 'safe-local-variable `stringp) +(defcustom verilog-auto-wire-comment t + "Non-nil indicates to insert to/from comments with `verilog-auto-wire' etc." + :version "25.1" + :group 'verilog-mode-actions + :type 'boolean) +(put 'verilog-auto-wire-comment 'safe-local-variable `verilog-booleanp) + (defcustom verilog-auto-wire-type nil "Non-nil specifies the data type to use with `verilog-auto-wire' etc. Set this to \"logic\" for SystemVerilog code, or use `verilog-auto-logic'." @@ -1131,32 +1138,67 @@ be replaced, and will remain symbolic. For example, imagine a submodule uses parameters to declare the size of its inputs. This is then used by an upper module: - module InstModule (o,i); - parameter WIDTH; - input [WIDTH-1:0] i; - endmodule + module InstModule (o,i); + parameter WIDTH; + input [WIDTH-1:0] i; + parameter type OUT_t; + output OUT_t o; + endmodule - module ExampInst; - InstModule - #(.PARAM(10)) - instName - (/*AUTOINST*/ - .i (i[PARAM-1:0])); + module ExampInst; + /*AUTOOUTPUT*/ + // Beginning of automatic outputs + output OUT_t o; + // End of automatics + + InstModule + #(.WIDTH(10), + ,.OUT_t(upper_t)) + instName + (/*AUTOINST*/ + .i (i[WIDTH-1:0]), + .o (o)); + +Note even though WIDTH=10, the AUTOINST has left the parameter as +a symbolic name. Likewise the OUT_t is preserved as the name +from the instantiated module. -Note even though PARAM=10, the AUTOINST has left the parameter as a -symbolic name. If `verilog-auto-inst-param-value' is set, this will +If `verilog-auto-inst-param-value' is set, this will instead expand to: module ExampInst; - InstModule - #(.PARAM(10)) - instName - (/*AUTOINST*/ - .i (i[9:0]));" + /*AUTOOUTPUT*/ + // Beginning of automatic outputs + output upper_t o; + // End of automatics + + InstModule + #(.WIDTH(10), + ,.OUT_t(upper_t)) + instName + (/*AUTOINST*/ + .i (i[9:0]), + .o (o)); + +Note that the instantiation now has \"i[9:0]\" as the WIDTH +was expanded. Likewise the data type of \"o\" in the AUTOOUTPUT +is now upper_t, from the OUT_t parameter override. +This second expansion of parameter types can be overridden with +`verilog-auto-inst-param-value-type'." :group 'verilog-mode-auto :type 'boolean) (put 'verilog-auto-inst-param-value 'safe-local-variable 'verilog-booleanp) +(defcustom verilog-auto-inst-param-value-type t + "Non-nil means expand parameter type in instantiations. +If nil, leave parameter types as symbolic names. + +See `verilog-auto-inst-param-value'." + :version "25.1" + :group 'verilog-mode-auto + :type 'boolean) +(put 'verilog-auto-inst-param-value-type 'safe-local-variable 'verilog-booleanp) + (defcustom verilog-auto-inst-sort nil "Non-nil means AUTOINST signals will be sorted, not in declaration order. Also affects AUTOINSTPARAM. Declaration order is the default for @@ -1761,7 +1803,7 @@ so there may be a large up front penalty for the first search." (let (pt) (while (and (not pt) (re-search-forward regexp bound noerror)) - (if (verilog-inside-comment-or-string-p) + (if (verilog-inside-comment-or-string-p (match-beginning 0)) (re-search-forward "[/\"\n]" nil t) ; Only way a comment or quote can end (setq pt (match-end 0)))) pt)) @@ -1775,7 +1817,7 @@ so there may be a large up front penalty for the first search." (let (pt) (while (and (not pt) (re-search-backward regexp bound noerror)) - (if (verilog-inside-comment-or-string-p) + (if (verilog-inside-comment-or-string-p (match-beginning 0)) (re-search-backward "[/\"]" nil t) ; Only way a comment or quote can begin (setq pt (match-beginning 0)))) pt)) @@ -2561,15 +2603,15 @@ find the errors." "\\|\\(\\\\)" ;7 "\\|\\(\\\\)" ;8 "\\|\\(\\\\)" ;9 - "\\|\\(\\(\\(\\\\s-+\\)\\|\\(\\\\s-+\\)\\)*\\\\)" ;10 - "\\|\\(\\\\)" ;14 - "\\|\\(\\(\\(\\\\s-+\\)\\|\\(\\\\s-+\\)\\)*\\\\)" ;15 - "\\|\\(\\\\)" ;18 - "\\|\\(\\\\)" ;16 20 - "\\|\\(\\(\\(\\\\s-+\\)\\|\\(\\\\s-+\\)\\)*\\\\)" ;17 21 - "\\|\\(\\<\\(rand\\)?sequence\\>\\)" ;21 25 - "\\|\\(\\\\)" ;22 27 - "\\|\\(\\<`[ou]vm_[a-z_]+_begin\\>\\)" ;28 + "\\|\\(\\(?:\\<\\(?:virtual\\|protected\\|static\\)\\>\\s-+\\)*\\\\)" ;10 + "\\|\\(\\\\)" ;11 + "\\|\\(\\(?:\\<\\(?:virtual\\|protected\\|static\\)\\>\\s-+\\)*\\\\)" ;12 + "\\|\\(\\\\)" ;13 + "\\|\\(\\\\)" ;14 + "\\|\\(\\(?:\\(?:\\\\s-+\\)\\|\\(?:\\\\s-+\\)\\)*\\\\)" ;15 + "\\|\\(\\<\\(?:rand\\)?sequence\\>\\)" ;16 + "\\|\\(\\\\)" ;17 + "\\|\\(\\<`[ou]vm_[a-z_]+_begin\\>\\)" ;18 "\\|\\(\\<`vmm_[a-z_]+_member_begin\\>\\)" ;; )) @@ -2812,10 +2854,12 @@ find the errors." "\\(\\<\\(import\\|export\\)\\>\\s-+\"DPI\\(-C\\)?\"\\s-+\\(\\<\\(context\\|pure\\)\\>\\s-+\\)?\\([A-Za-z_][A-Za-z0-9_]*\\s-*=\\s-*\\)?\\<\\(function\\|task\\)\\>\\)" )) +(defconst verilog-default-clocking-re "\\") (defconst verilog-disable-fork-re "\\(disable\\|wait\\)\\s-+fork\\>") -(defconst verilog-extended-case-re "\\(\\(unique0?\\s-+\\|priority\\s-+\\)?case[xz]?\\)") +(defconst verilog-extended-case-re "\\(\\(unique0?\\s-+\\|priority\\s-+\\)?case[xz]?\\|randcase\\)") (defconst verilog-extended-complete-re - (concat "\\(\\(\\\\s-+\\)?virtual\\s-+\\|\\\\|\\\\)\\)" + ;; verilog-beg-of-statement also looks backward one token to extend this match + (concat "\\(\\(\\\\s-+\\)?virtual\\s-+\\|\\\\|\\\\)\\)" "\\|\\(\\(\\\\s-+\\)*\\(\\\\|\\\\|\\\\)\\)" "\\|\\(\\(\\<\\(import\\|export\\)\\>\\s-+\\)?\\(\"DPI\\(-C\\)?\"\\s-+\\)?\\(\\<\\(pure\\|context\\)\\>\\s-+\\)?\\([A-Za-z_][A-Za-z0-9_]*\\s-*=\\s-*\\)?\\(function\\>\\|task\\>\\)\\)" "\\|" verilog-extended-case-re )) @@ -3584,28 +3628,28 @@ Use filename, if current buffer being edited shorten to just buffer name." ;; Search forward for matching endfunction (setq reg "\\" ) (setq nest 'no)) - ((match-end 14) + ((match-end 11) ;; Search forward for matching endtask (setq reg "\\" ) (setq nest 'no)) - ((match-end 15) + ((match-end 12) ;; Search forward for matching endtask (setq reg "\\" ) (setq nest 'no)) - ((match-end 19) + ((match-end 12) ;; Search forward for matching endgenerate (setq reg "\\(\\\\)\\|\\(\\\\)" )) - ((match-end 20) + ((match-end 13) ;; Search forward for matching endgroup (setq reg "\\(\\\\)\\|\\(\\\\)" )) - ((match-end 21) + ((match-end 14) ;; Search forward for matching endproperty (setq reg "\\(\\\\)\\|\\(\\\\)" )) - ((match-end 25) + ((match-end 15) ;; Search forward for matching endsequence (setq reg "\\(\\<\\(rand\\)?sequence\\>\\)\\|\\(\\\\)" ) (setq md 3)) ; 3 to get to endsequence in the reg above - ((match-end 27) + ((match-end 17) ;; Search forward for matching endclocking (setq reg "\\(\\\\)\\|\\(\\\\)" ))) (if (and reg @@ -3884,7 +3928,10 @@ Key bindings specific to `verilog-mode-map' are: ;;; Integration with the speedbar ;; -(declare-function speedbar-add-supported-extension "speedbar" (extension)) +;; Avoid problems with XEmacs byte-compiles. +;; For GNU Emacs, the eval-after-load will handle if it isn't loaded yet. +(when (eval-when-compile (fboundp 'declare-function)) + (declare-function speedbar-add-supported-extension "speedbar" (extension))) (defun verilog-speedbar-initialize () "Initialize speedbar to understand `verilog-mode'." @@ -4566,7 +4613,7 @@ Limit search to point LIM." (progn (if (verilog-re-search-backward - "\\<\\(case[zx]?\\)\\>\\|;\\|\\" nil 'move) + "\\<\\(randcase\\|case[zx]?\\)\\>\\|;\\|\\" nil 'move) (progn (cond ((match-end 1) @@ -5692,13 +5739,17 @@ Return a list of two elements: (INDENT-TYPE INDENT-LEVEL)." (goto-char here) (throw 'nesting 'block))))) - ((match-end 27) ; *sigh* might be a clocking declaration + ((match-end 17) ; *sigh* might be a clocking declaration (let ((here (point))) - (if (verilog-in-paren) - t ; this is a normal statement - (progn ; or is fork, starts a new block - (goto-char here) - (throw 'nesting 'block))))) + (cond ((verilog-in-paren) + t) ; this is a normal statement + ((save-excursion + (verilog-beg-of-statement) + (looking-at verilog-default-clocking-re)) + t) ; default clocking, normal statement + (t + (goto-char here) ; or is clocking, starts a new block + (throw 'nesting 'block))))) ;; need to consider typedef struct here... ((looking-at "\\") @@ -5826,7 +5877,7 @@ Jump from end to matching begin, from endcase to matching case, and so on." "\\(\\\\)\\|\\(\\\\)" ))) ((looking-at "\\") ;; 2: Search back for matching task - (setq reg "\\(\\\\)\\|\\(\\(\\(\\\\s-+\\)\\|\\(\\\\s-+\\)\\)+\\\\)") + (setq reg "\\(\\\\)\\|\\(\\(\\<\\(virtual\\|protected\\|static\\)\\>\\s-+\\)+\\\\)") (setq nesting 'no)) ((looking-at "\\") (catch 'nesting @@ -5848,7 +5899,7 @@ Jump from end to matching begin, from endcase to matching case, and so on." (setq reg "\\(\\\\)\\|\\(\\\\)" )) ((looking-at "\\") ;; 8: Search back for matching function - (setq reg "\\(\\\\)\\|\\(\\(\\(\\\\s-+\\)\\|\\(\\\\s-+\\)\\)+\\\\)") + (setq reg "\\(\\\\)\\|\\(\\(\\<\\(virtual\\|protected\\|static\\)\\>\\s-+\\)+\\\\)") (setq nesting 'no)) ;;(setq reg "\\(\\\\)\\|\\(\\\\)" )) ((looking-at "\\") @@ -6300,7 +6351,7 @@ Return >0 for nested struct." (let ((p (point))) (and (equal (char-after) ?\{) - (forward-list) + (ignore-errors (forward-list)) (progn (backward-char 1) (verilog-backward-ws&directives) (and @@ -7831,7 +7882,7 @@ See also `verilog-sk-header' for an alternative format." (if (verilog-sig-multidim sig) (let ((str "") (args (verilog-sig-multidim sig))) (while args - (setq str (concat str (car args))) + (setq str (concat (car args) str)) (setq args (cdr args))) str))) (defsubst verilog-sig-modport (sig) @@ -8352,7 +8403,8 @@ Return an array of [outputs inouts inputs wire reg assign const]." in-modport in-clocking in-ign-to-semi ptype ign-prop sigs-in sigs-out sigs-inout sigs-var sigs-assign sigs-const sigs-gparam sigs-intf sigs-modports - vec expect-signal keywd newsig rvalue enum io signed typedefed multidim + vec expect-signal keywd last-keywd newsig rvalue enum io + signed typedefed multidim modport varstack tmp) ;;(if dbg (setq dbg (concat dbg (format "\n\nverilog-read-decls START PT %s END %s\n" (point) end-mod-point)))) @@ -8433,7 +8485,8 @@ Return an array of [outputs inouts inputs wire reg assign const]." ;; Normal or escaped identifier -- note we remember the \ if escaped ((looking-at "\\s-*\\([a-zA-Z0-9`_$]+\\|\\\\[^ \t\n\f]+\\)") (goto-char (match-end 0)) - (setq keywd (match-string-no-properties 1)) + (setq last-keywd keywd + keywd (match-string-no-properties 1)) (when (string-match "^\\\\" (match-string 1)) (setq keywd (concat keywd " "))) ; Escaped ID needs space at end ;; Add any :: package names to same identifier @@ -8498,7 +8551,8 @@ Return an array of [outputs inouts inputs wire reg assign const]." (setq functask (1- functask))) ((equal keywd "modport") (setq in-modport t)) - ((equal keywd "clocking") + ((and (equal keywd "clocking") + (not (equal last-keywd "default"))) (setq in-clocking t)) ((equal keywd "import") (if v2kargs-ok ; import in module header, not a modport import @@ -8623,12 +8677,20 @@ Return an array of [outputs inouts inputs wire reg assign const]." (defvar create-lockfiles) (defvar which-func-modes)) -(defun verilog-read-sub-decls-sig (submoddecls comment port sig vec multidim mem) +(defun verilog-read-sub-decls-type (par-values portdata) + "For `verilog-read-sub-decls-line', decode a signal type." + (let* ((type (verilog-sig-type portdata)) + (pvassoc (assoc type par-values))) + (cond ((member type '("wire" "reg")) nil) + (pvassoc (nth 1 pvassoc)) + (t type)))) + +(defun verilog-read-sub-decls-sig (submoddecls par-values comment port sig vec multidim mem) "For `verilog-read-sub-decls-line', add a signal." ;; sig eq t to indicate .name syntax ;;(message "vrsds: %s(%S)" port sig) (let ((dotname (eq sig t)) - portdata) + portdata) (when sig (setq port (verilog-symbol-detick-denumber port)) (setq sig (if dotname port (verilog-symbol-detick-denumber sig))) @@ -8647,8 +8709,7 @@ Return an array of [outputs inouts inputs wire reg assign const]." mem nil (verilog-sig-signed portdata) - (unless (member (verilog-sig-type portdata) '("wire" "reg")) - (verilog-sig-type portdata)) + (verilog-read-sub-decls-type par-values portdata) multidim nil) sigs-inout))) ((or (setq portdata (assoc port (verilog-decls-get-outputs submoddecls))) @@ -8666,8 +8727,7 @@ Return an array of [outputs inouts inputs wire reg assign const]." ;; Also for backwards compatibility we don't propagate ;; "input wire" upwards. ;; See also `verilog-signals-edit-wire-reg'. - (unless (member (verilog-sig-type portdata) '("wire" "reg")) - (verilog-sig-type portdata)) + (verilog-read-sub-decls-type par-values portdata) multidim nil) sigs-out))) ((or (setq portdata (assoc port (verilog-decls-get-inputs submoddecls))) @@ -8680,8 +8740,7 @@ Return an array of [outputs inouts inputs wire reg assign const]." mem nil (verilog-sig-signed portdata) - (unless (member (verilog-sig-type portdata) '("wire" "reg")) - (verilog-sig-type portdata)) + (verilog-read-sub-decls-type par-values portdata) multidim nil) sigs-in))) ((setq portdata (assoc port (verilog-decls-get-interfaces submoddecls))) @@ -8693,7 +8752,7 @@ Return an array of [outputs inouts inputs wire reg assign const]." mem nil (verilog-sig-signed portdata) - (verilog-sig-type portdata) + (verilog-read-sub-decls-type par-values portdata) multidim nil) sigs-intf))) ((setq portdata (and verilog-read-sub-decls-in-interfaced @@ -8706,13 +8765,13 @@ Return an array of [outputs inouts inputs wire reg assign const]." mem nil (verilog-sig-signed portdata) - (verilog-sig-type portdata) + (verilog-read-sub-decls-type par-values portdata) multidim nil) sigs-intf))) ;; (t -- warning pin isn't defined.) ; Leave for lint tool ))))) -(defun verilog-read-sub-decls-expr (submoddecls comment port expr) +(defun verilog-read-sub-decls-expr (submoddecls par-values comment port expr) "For `verilog-read-sub-decls-line', parse a subexpression and add signals." ;;(message "vrsde: `%s'" expr) ;; Replace special /*[....]*/ comments inserted by verilog-auto-inst-port @@ -8728,7 +8787,7 @@ Return an array of [outputs inouts inputs wire reg assign const]." (let ((mlst (split-string (match-string 1 expr) "[{},]")) mstr) (while (setq mstr (pop mlst)) - (verilog-read-sub-decls-expr submoddecls comment port mstr))))) + (verilog-read-sub-decls-expr submoddecls par-values comment port mstr))))) (t (let (sig vec multidim mem) ;; Remove leading reduction operators, etc @@ -8751,16 +8810,16 @@ Return an array of [outputs inouts inputs wire reg assign const]." (setq vec (match-string 1 expr) expr (substring expr (match-end 0)))) ;; Find .[unpacked_memory] or .[unpacked][unpacked]... - (while (string-match "^\\s-*\\.\\(\\[[^]]+\\]\\)" expr) + (while (string-match "^\\s-*\\.\\(\\(\\[[^]]+\\]\\)+\\)" expr) ;;(message "vrsde-m: `%s'" (match-string 1 expr)) (setq mem (match-string 1 expr) expr (substring expr (match-end 0)))) ;; If found signal, and nothing unrecognized, add the signal ;;(message "vrsde-rem: `%s'" expr) (when (and sig (string-match "^\\s-*$" expr)) - (verilog-read-sub-decls-sig submoddecls comment port sig vec multidim mem)))))) + (verilog-read-sub-decls-sig submoddecls par-values comment port sig vec multidim mem)))))) -(defun verilog-read-sub-decls-line (submoddecls comment) +(defun verilog-read-sub-decls-line (submoddecls par-values comment) "For `verilog-read-sub-decls', read lines of port defs until none match. Inserts the list of signals found, using submodi to look up each port." (let (done port) @@ -8778,13 +8837,13 @@ Inserts the list of signals found, using submodi to look up each port." ;; .name ((looking-at "\\s-*\\.\\s-*\\([a-zA-Z0-9`_$]*\\)\\s-*[,)/]") (verilog-read-sub-decls-sig - submoddecls comment (match-string-no-properties 1) t ; sig==t for .name + submoddecls par-values comment (match-string-no-properties 1) t ; sig==t for .name nil nil nil) ; vec multidim mem (setq port nil)) ;; .\escaped_name ((looking-at "\\s-*\\.\\s-*\\(\\\\[^ \t\n\f]*\\)\\s-*[,)/]") (verilog-read-sub-decls-sig - submoddecls comment (concat (match-string-no-properties 1) " ") t ; sig==t for .name + submoddecls par-values comment (concat (match-string-no-properties 1) " ") t ; sig==t for .name nil nil nil) ; vec multidim mem (setq port nil)) ;; random @@ -8799,28 +8858,29 @@ Inserts the list of signals found, using submodi to look up each port." (when port (cond ((looking-at "\\([a-zA-Z_][a-zA-Z_0-9]*\\)\\s-*)") (verilog-read-sub-decls-sig - submoddecls comment port + submoddecls par-values comment port (verilog-string-remove-spaces (match-string-no-properties 1)) ; sig nil nil nil)) ; vec multidim mem ;; ((looking-at "\\([a-zA-Z_][a-zA-Z_0-9]*\\)\\s-*\\(\\[[^]]+\\]\\)\\s-*)") (verilog-read-sub-decls-sig - submoddecls comment port + submoddecls par-values comment port (verilog-string-remove-spaces (match-string-no-properties 1)) ; sig (match-string-no-properties 2) nil nil)) ; vec multidim mem ;; Fastpath was above looking-at's. ;; For something more complicated invoke a parser ((looking-at "[^)]+") (verilog-read-sub-decls-expr - submoddecls comment port + submoddecls par-values comment port (buffer-substring-no-properties (point) (1- (progn (search-backward "(") ; start at ( (verilog-forward-sexp-ign-cmt 1) (point)))))))) ; expr ;; (forward-line 1))))) +;;(verilog-read-sub-decls-line (verilog-subdecls-new nil nil nil nil nil) nil "Cmt") -(defun verilog-read-sub-decls-gate (submoddecls comment submod end-inst-point) +(defun verilog-read-sub-decls-gate (submoddecls par-values comment submod end-inst-point) "For `verilog-read-sub-decls', read lines of UDP gate decl until none match. Inserts the list of signals found." (save-excursion @@ -8844,7 +8904,7 @@ Inserts the list of signals found." (setq verilog-read-sub-decls-gate-ios (or (car iolist) "input") iolist (cdr iolist)) (verilog-read-sub-decls-expr - submoddecls comment "primitive_port" + submoddecls par-values comment "primitive_port" (match-string 0))) (t (forward-char 1) @@ -8870,13 +8930,16 @@ Outputs comments above subcell signals, for example: .in (in));" (save-excursion (let ((end-mod-point (verilog-get-end-of-defun)) - st-point end-inst-point + st-point end-inst-point par-values ;; below 3 modified by verilog-read-sub-decls-line sigs-out sigs-inout sigs-in sigs-intf sigs-intfd) (verilog-beg-of-defun-quick) (while (verilog-re-search-forward-quick "\\(/\\*AUTOINST\\*/\\|\\.\\*\\)" end-mod-point t) (save-excursion (goto-char (match-beginning 0)) + (setq par-values (and verilog-auto-inst-param-value + verilog-auto-inst-param-value-type + (verilog-read-inst-param-value))) (unless (verilog-inside-comment-or-string-p) ;; Attempt to snarf a comment (let* ((submod (verilog-read-inst-module)) @@ -8894,7 +8957,7 @@ Outputs comments above subcell signals, for example: (point)) st-point (point)) (forward-char 1) - (verilog-read-sub-decls-gate submoddecls comment submod end-inst-point)) + (verilog-read-sub-decls-gate submoddecls par-values comment submod end-inst-point)) ;; Non-primitive (t (when (setq submodi (verilog-modi-lookup submod t)) @@ -8908,19 +8971,19 @@ Outputs comments above subcell signals, for example: ;; However I want it to be runnable even on user's manually added signals (let ((verilog-read-sub-decls-in-interfaced t)) (while (re-search-forward "\\s *(?\\s *// Interfaced" end-inst-point t) - (verilog-read-sub-decls-line submoddecls comment))) ; Modifies sigs-ifd + (verilog-read-sub-decls-line submoddecls par-values comment))) ; Modifies sigs-ifd (goto-char st-point) (while (re-search-forward "\\s *(?\\s *// Interfaces" end-inst-point t) - (verilog-read-sub-decls-line submoddecls comment)) ; Modifies sigs-out + (verilog-read-sub-decls-line submoddecls par-values comment)) ; Modifies sigs-out (goto-char st-point) (while (re-search-forward "\\s *(?\\s *// Outputs" end-inst-point t) - (verilog-read-sub-decls-line submoddecls comment)) ; Modifies sigs-out + (verilog-read-sub-decls-line submoddecls par-values comment)) ; Modifies sigs-out (goto-char st-point) (while (re-search-forward "\\s *(?\\s *// Inouts" end-inst-point t) - (verilog-read-sub-decls-line submoddecls comment)) ; Modifies sigs-inout + (verilog-read-sub-decls-line submoddecls par-values comment)) ; Modifies sigs-inout (goto-char st-point) (while (re-search-forward "\\s *(?\\s *// Inputs" end-inst-point t) - (verilog-read-sub-decls-line submoddecls comment)) ; Modifies sigs-in + (verilog-read-sub-decls-line submoddecls par-values comment)) ; Modifies sigs-in ))))))) ;; Combine duplicate bits ;;(setq rr (vector sigs-out sigs-inout sigs-in)) @@ -9111,7 +9174,7 @@ IGNORE-NEXT is true to ignore next token, fake from inside case statement." ;;(if dbg (setq dbg (concat dbg (format "\tgot-end %s\n" exit-keywd)))) (setq ignore-next nil rvalue semi-rvalue) (if (not exit-keywd) (setq end-else-check t))) - ((member keywd '("case" "casex" "casez")) + ((member keywd '("case" "casex" "casez" "randcase")) (skip-syntax-forward "w_") (verilog-read-always-signals-recurse "endcase" t nil) (setq ignore-next nil rvalue semi-rvalue) @@ -9337,29 +9400,43 @@ Optionally associate it with the specified enumeration ENUMNAME." If the filename is provided, `verilog-library-flags' will be used to resolve it. If optional RECURSE is non-nil, recurse through \\=`includes. -Parameters must be simple assignments to constants, or have their own -\"parameter\" label rather than a list of parameters. Thus: +Localparams must be simple assignments to constants, or have their own +\"localparam\" label rather than a list of localparams. Thus: - parameter X = 5, Y = 10; // Ok - parameter X = {1\\='b1, 2\\='h2}; // Ok - parameter X = {1\\='b1, 2\\='h2}, Y = 10; // Bad, make into 2 parameter lines + localparam X = 5, Y = 10; // Ok + localparam X = {1\\='b1, 2\\='h2}; // Ok + localparam X = {1\\='b1, 2\\='h2}, Y = 10; // Bad, make into 2 localparam lines Defines must be simple text substitutions, one on a line, starting at the beginning of the line. Any ifdefs or multiline comments around the define are ignored. -Defines are stored inside Emacs variables using the name vh-{definename}. +Defines are stored inside Emacs variables using the name +vh-{definename}. -This function is useful for setting vh-* variables. The file variables -feature can be used to set defines that `verilog-mode' can see; put at the -*END* of your file something like: +Localparams define what symbols are constants so that AUTOSENSE +will not include them in sensitivity lists. However any +parameters in the include file are not considered ports in the +including file, thus will not appear in AUTOINSTPARAM lists for a +parent module.. + +The file variables feature can be used to set defines that +`verilog-mode' can see; put at the *END* of your file something +like: // Local Variables: // vh-macro:\"macro_definition\" // End: If macros are defined earlier in the same file and you want their values, -you can read them automatically (provided `enable-local-eval' is on): +you can read them automatically with: + + // Local Variables: + // verilog-auto-read-includes:t + // End: + +Or a more specific alternative example, which requires haing +`enable-local-eval' non-nil: // Local Variables: // eval:(verilog-read-defines) @@ -9427,6 +9504,13 @@ file. It is often useful put at the *END* of your file something like: // Local Variables: + // verilog-auto-read-includes:t + // End: + +Or the equivalent longer version, which requires having +`enable-local-eval' non-nil: + + // Local Variables: // eval:(verilog-read-defines) // eval:(verilog-read-includes) // End: @@ -9848,9 +9932,14 @@ Uses the CURRENT filename, `verilog-library-extensions', `verilog-library-directories' and `verilog-library-files' variables to build the path." ;; Return search locations for it - (append (list current) ; first, current buffer - (verilog-library-filenames module current t) - verilog-library-files)) ; finally, any libraries + (append (list current) ; first, current buffer + (verilog-library-filenames module current t) + ;; Finally any libraries; fixed up if using e.g. tramp + (mapcar (lambda (fname) + (if (file-name-absolute-p fname) + (concat (file-remote-p current) fname) + fname)) + verilog-library-files))) ;; ;; Module Information @@ -10270,8 +10359,9 @@ When MODI is non-null, also add to modi-cache, for tracking." direction)) indent-pt) (insert (if v2k "," ";")) - (if (or (not (verilog-sig-comment sig)) - (equal "" (verilog-sig-comment sig))) + (if (or (not verilog-auto-wire-comment) + (not (verilog-sig-comment sig)) + (equal "" (verilog-sig-comment sig))) (insert "\n") (indent-to (max 48 (+ indent-pt 40))) (verilog-insert "// " (verilog-sig-comment sig) "\n")) @@ -10821,9 +10911,9 @@ Ignores WHITESPACE if t, and writes output to stdout if SHOW." Differences are between buffers B1 and B2, starting at point DIFFPT. This function is called via `verilog-diff-function'." (let ((name1 (with-current-buffer b1 (buffer-file-name)))) - (verilog-warn "%s:%d: Difference in AUTO expansion found" - name1 (with-current-buffer b1 - (count-lines (point-min) diffpt))) + (verilog-warn-error "%s:%d: Difference in AUTO expansion found" + name1 (with-current-buffer b1 + (count-lines (point-min) diffpt))) (cond (noninteractive (verilog-diff-file-with-buffer name1 b2 t t)) (t @@ -13040,7 +13130,7 @@ Typing \\[verilog-auto] will make this into: (verilog-read-signals (save-excursion (verilog-re-search-backward-quick - "\\(@\\|\\<\\(begin\\|if\\|case\\|always\\(_latch\\|_ff\\|_comb\\)?\\)\\>\\)" nil t) + "\\(@\\|\\<\\(begin\\|if\\|case[xz]?\\|always\\(_latch\\|_ff\\|_comb\\)?\\)\\>\\)" nil t) (point)) (point))))) (save-excursion commit 2f5e0b1bf7b0ac4f450847db34d599a072020600 Author: Paul Eggert Date: Mon Nov 14 09:08:06 2016 -0800 Improve case-insensitive checks (Bug#24441) * doc/lispref/files.texi (Truenames): Simplify documentation, to avoid giving too much platform-specific information that may not be accurate anyway. * src/fileio.c (file_name_case_insensitive_p): Use pathconf with _PC_CASE_SENSITIVE if _PC_CASE_INSENSITIVE is not available. Otherwise if one approach fails (e.g., with errno == EINVAL), fall back on an alternative rather than returning false. Try skipping the Darwin code, as it (1) no longer seems to be needed and (2) does not seem to match the Apple documentation. Leave in two alternatives conditionally compiled based on DARWIN_OS_CASE_SENSITIVE_FIXME in case (1) or (2) is incorrect. diff --git a/doc/lispref/files.texi b/doc/lispref/files.texi index 70c7177..ab0dcae 100644 --- a/doc/lispref/files.texi +++ b/doc/lispref/files.texi @@ -1144,17 +1144,9 @@ return value is unspecified. Sometimes file names or their parts need to be compared as strings, in which case it's important to know whether the underlying filesystem is case-insensitive. This function returns @code{t} if file -@var{filename} is on a case-insensitive filesystem. It always returns -@code{t} on MS-DOS and MS-Windows. On Cygwin and Mac OS X, -filesystems may or may not be case-insensitive, and the function tries -to determine case-sensitivity by a runtime test. If the test is -inconclusive, the function returns @code{t} on Cygwin and @code{nil} -on Mac OS X. - -Currently this function always returns @code{nil} on platforms other -than MS-DOS, MS-Windows, Cygwin, and Mac OS X. It does not detect -case-insensitivity of mounted filesystems, such as Samba shares or -NFS-mounted Windows volumes. +@var{filename} is on a case-insensitive filesystem. On platforms where +this information is not available, this function guesses based on +common practice. @end defun @defun file-in-directory-p file dir diff --git a/src/fileio.c b/src/fileio.c index f3f8f42..eec3591 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -2236,13 +2236,10 @@ internal_delete_file (Lisp_Object filename) return NILP (tem); } -/* Filesystems are case-sensitive on all supported systems except - MS-Windows, MS-DOS, Cygwin, and Mac OS X. They are always - case-insensitive on the first two, but they may or may not be - case-insensitive on Cygwin and OS X. The following function - attempts to provide a runtime test on those two systems. If the - test is not conclusive, we assume case-insensitivity on Cygwin and - case-sensitivity on Mac OS X. +/* Return true if FILENAME is on a case-insensitive file system. + Use a runtime test if available. Otherwise, assume the file system + is case-insensitive on Microsoft-based platforms and case-sensitive + elsewhere. FIXME: Mounted filesystems on Posix hosts, like Samba shares or NFS-mounted Windows volumes, might be case-insensitive. Can we @@ -2251,33 +2248,65 @@ internal_delete_file (Lisp_Object filename) static bool file_name_case_insensitive_p (const char *filename) { -#ifdef DOS_NT - return 1; -#elif defined CYGWIN -/* As of Cygwin-2.6.1, pathconf supports _PC_CASE_INSENSITIVE. */ -# ifdef _PC_CASE_INSENSITIVE +#ifdef _PC_CASE_INSENSITIVE int res = pathconf (filename, _PC_CASE_INSENSITIVE); - if (res < 0) - return 1; - return res > 0; -# else - return 1; + if (0 < res) + return true; + if (res == 0 || errno != EINVAL) + return false; +#elif defined _PC_CASE_SENSITIVE + int res = pathconf (filename, _PC_CASE_SENSITIVE); + if (res == 0) + return true; + if (0 < res || errno != EINVAL) + return false; +#endif + +#ifdef DARWIN_OS + /* It is not clear whether this section is needed. For now, rely on + pathconf and skip this section. If pathconf does not work, + please recompile Emacs with -DDARWIN_OS_CASE_SENSITIVE_FIXME=1 or + -DDARWIN_OS_CASE_SENSITIVE_FIXME=2, and file a bug report saying + whether this fixed your problem. */ +# ifndef DARWIN_OS_CASE_SENSITIVE_FIXME + int DARWIN_OS_CASE_SENSITIVE_FIXME = 0; # endif -#elif defined DARWIN_OS - /* The following is based on - http://lists.apple.com/archives/darwin-dev/2007/Apr/msg00010.html. */ - struct attrlist alist; - unsigned char buffer[sizeof (vol_capabilities_attr_t) + sizeof (size_t)]; - - memset (&alist, 0, sizeof (alist)); - alist.volattr = ATTR_VOL_CAPABILITIES; - if (getattrlist (filename, &alist, buffer, sizeof (buffer), 0) - || !(alist.volattr & ATTR_VOL_CAPABILITIES)) - return 0; - vol_capabilities_attr_t *vcaps = buffer; - return !(vcaps->capabilities[0] & VOL_CAP_FMT_CASE_SENSITIVE); + + if (DARWIN_OS_CASE_SENSITIVE_FIXME == 1) + { + /* This is based on developer.apple.com's getattrlist man page. */ + struct attrlist alist = {.volattr = ATTR_VOL_CAPABILITIES}; + struct vol_capabilities_attr_t vcaps; + if (getattrlist (filename, &alist, &vcaps, sizeof vcaps, 0) == 0) + { + if (vcaps.valid[VOL_CAPABILITIES_FORMAT] & VOL_CAP_FMT_CASE_SENSITIVE) + return ! (vcaps.capabilities[VOL_CAPABILITIES_FORMAT] + & VOL_CAP_FMT_CASE_SENSITIVE); + } + else if (errno != EINVAL) + return false; + } + else if (DARWIN_OS_CASE_SENSITIVE_FIXME == 2) + { + /* The following is based on + http://lists.apple.com/archives/darwin-dev/2007/Apr/msg00010.html. */ + struct attrlist alist; + unsigned char buffer[sizeof (vol_capabilities_attr_t) + sizeof (size_t)]; + + memset (&alist, 0, sizeof (alist)); + alist.volattr = ATTR_VOL_CAPABILITIES; + if (getattrlist (filename, &alist, buffer, sizeof (buffer), 0) + || !(alist.volattr & ATTR_VOL_CAPABILITIES)) + return 0; + vol_capabilities_attr_t *vcaps = buffer; + return !(vcaps->capabilities[0] & VOL_CAP_FMT_CASE_SENSITIVE); + } +#endif + +#if defined CYGWIN || defined DOS_NT + return true; #else - return 0; + return false; #endif } @@ -2349,7 +2378,7 @@ This is what happens in interactive use with M-x. */) /* If the filesystem is case-insensitive and the file names are identical but for the case, don't ask for confirmation: they simply want to change the letter-case of the file name. */ - if ((!(file_name_case_insensitive_p (SSDATA (encoded_file))) + if ((! file_name_case_insensitive_p (SSDATA (encoded_file)) || NILP (Fstring_equal (Fdowncase (file), Fdowncase (newname)))) && ((NILP (ok_if_already_exists) || INTEGERP (ok_if_already_exists)))) barf_or_query_if_file_exists (newname, false, "rename to it", commit 3625e6ce9352942a4db980dd203b590cdaf821df Author: Eli Zaretskii Date: Mon Nov 14 18:13:09 2016 +0200 Fix documentation changes of connection-local variables * etc/NEWS: Fix last change. * doc/lispref/variables.texi (Connection Local Variables): Minor fixes. * doc/lispref/elisp.texi (Top): Update the master menu. diff --git a/doc/lispref/elisp.texi b/doc/lispref/elisp.texi index 4a1e528..708bd9c 100644 --- a/doc/lispref/elisp.texi +++ b/doc/lispref/elisp.texi @@ -503,6 +503,7 @@ Variables * File Local Variables:: Handling local variable lists in files. * Directory Local Variables:: Local variables common to all files in a directory. +* Connection Local Variables:: Local variables common for remote connections. * Variable Aliases:: Variables that are aliases for other variables. * Variables with Restricted Values:: Non-constant variables whose value can @emph{not} be an arbitrary Lisp object. diff --git a/doc/lispref/variables.texi b/doc/lispref/variables.texi index 8a17797..4f2274f 100644 --- a/doc/lispref/variables.texi +++ b/doc/lispref/variables.texi @@ -2001,10 +2001,10 @@ buffers, it could be called by any mode. @defmac with-connection-local-classes classes &rest body All connection-local variables, which are specified by a class in -@var{CLASSES}, are applied. An implicit binding of the classes to the +@var{classes}, are applied. An implicit binding of the classes to the remote connection is enabled. -After that, @var{BODY} is executed, and the connection-local variables +After that, @var{body} is executed, and the connection-local variables are unwound. Example: @example diff --git a/etc/NEWS b/etc/NEWS index 2e72fd5..34d64bf 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -225,8 +225,8 @@ See the variable 'dir-locals-file-2' for more information. +++ ** Connection-local variables can be used to specify local variables -with a value depending on the connected remote server. For details, see -(info "(elisp)Connection Local Variables") +with a value depending on the connected remote server. For details, +see the node "Connection Local Variables" in the ELisp manual. --- ** International domain names (IDNA) are now encoded via the new commit 6647e05174ade1132a957e7e27f9ef6e96f3f9d7 Author: Michael Albinus Date: Mon Nov 14 13:56:58 2016 +0100 Implement connection-local variables * doc/lispref/variables.texi (Connection Local Variables): New section. * etc/NEWS: Mention connection-local variables. * lisp/files-x.el (enable-connection-local-variables) (connection-local-variables-alist, connection-local-class-alist) (connection-local-criteria-alist): New defvars. (connection-local-get-classes) (connection-local-get-class-variables): New defsubst. (connection-local-set-classes) (connection-local-set-class-variables) (hack-connection-local-variables) (hack-connection-local-variables-apply): New defuns. (with-connection-local-classes): New defmacro. * lisp/net/tramp.el (tramp-set-connection-local-variables): New defun. * lisp/net/tramp-adb.el (tramp-adb-maybe-open-connection): * lisp/net/tramp-gvfs.el (tramp-gvfs-maybe-open-connection): * lisp/net/lisp/net/tramp-sh.el (tramp-maybe-open-connection): * lisp/net/tramp-smb.el (tramp-smb-maybe-open-connection): Use it. * test/lisp/files-x-tests.el: New file. diff --git a/doc/lispref/variables.texi b/doc/lispref/variables.texi index 418a416..8a17797 100644 --- a/doc/lispref/variables.texi +++ b/doc/lispref/variables.texi @@ -38,6 +38,7 @@ representing the variable. * Buffer-Local Variables:: Variable values in effect only in one buffer. * File Local Variables:: Handling local variable lists in files. * Directory Local Variables:: Local variables common to all files in a directory. +* Connection Local Variables:: Local variables common for remote connections. * Variable Aliases:: Variables that are aliases for other variables. * Variables with Restricted Values:: Non-constant variables whose value can @emph{not} be an arbitrary Lisp object. @@ -1862,6 +1863,170 @@ may be useful for modes that want to ignore directory-locals while still respecting file-local variables (@pxref{File Local Variables}). @end defvar +@node Connection Local Variables +@section Connection Local Variables +@cindex connection local variables + + Connection-local variables provide a general mechanism for +different variable settings in buffers with a remote default +directory. They are bound and set depending on the remote connection +a buffer is dedicated to. Per default, they are set in all process +buffers for a remote connection, but they could be applied also in +other buffers with a remote directory. + +@defun connection-local-set-class-variables class variables +This function defines a set of variable settings for the named +@var{class}, which is a symbol. You can later assign the class to one +or more remote connections, and Emacs will apply those variable +settings to all process buffers for those connections. The list in +@var{variables} is an alist of the form @code{(@var{name} +. @var{value})}. Example: + +@example +@group +(connection-local-set-class-variables + 'remote-bash + '((shell-file-name . "/bin/bash") + (shell-command-switch . "-c") + (shell-interactive-switch . "-i") + (shell-login-switch . "-l"))) +@end group + +@group +(connection-local-set-class-variables + 'remote-ksh + '((shell-file-name . "/bin/ksh") + (shell-command-switch . "-c") + (shell-interactive-switch . "-i") + (shell-login-switch . "-l"))) +@end group + +@group +(connection-local-set-class-variables + 'remote-null-device + '((null-device "/dev/null"))) +@end group +@end example +@end defun + +@defvar connection-local-class-alist +This alist holds the class symbols and the associated variable +settings. It is updated by @code{connection-local-set-class-variables}. +@end defvar + +@defun connection-local-set-classes criteria &rest classes +This function assigns @var{classes}, which are symbols, to all remote +connections identified by @var{criteria}. @var{criteria} is either a +regular expression identifying a remote server, or a function with one +argument @var{identification}, which must return non-nil when a remote +server shall apply @var{classes} variables, or @code{nil}. + +If @var{criteria} is a regexp, is must match the result of +@code{(file-remote-p default-directory)} of a buffer in order to apply +the variables setting. Example: + +@example +@group +(connection-local-set-classes + "^/ssh:" 'remote-bash 'remote-null-device) +@end group + +@group +(connection-local-set-classes + "^/sudo:" 'remote-ksh 'remote-null-device) +@end group +@end example + + If @var{criteria} is nil, it applies for all remote connections. +Therefore, the example above would be equivalent to + +@example +(connection-local-set-classes "^/ssh:" 'remote-bash) +(connection-local-set-classes "^/sudo:" 'remote-ksh) +(connection-local-set-classes nil 'remote-null-device) +@end example + + If @var{criteria} is a lambda function it must accept one parameter, +the identification. The example above could be rewritten as + +@example +@group +(connection-local-set-classes + (lambda (identification) + (string-equal (file-remote-p identification 'method) "ssh")) + 'remote-bash) +@end group + +@group +(connection-local-set-classes + (lambda (identification) + (string-equal (file-remote-p identification 'method) "sudo")) + 'remote-ksh) +@end group + +@group +(connection-local-set-classes + (lambda (identification) t) + 'remote-null-device) +@end group +@end example + + Thereafter, all the variable settings specified for @var{classes} +will be applied to any buffer with a matching remote directory, when +activated by @code{hack-connection-local-variables-apply}. Any class +of @var{classes} must have been already defined by +@code{connection-local-set-class-variables}. +@end defun + +@defvar connection-local-criteria-alist +This alist contains remote server identifications and their assigned +class names. The function @code{connection-local-set-classes} updates +this list. +@end defvar + +@defun hack-connection-local-variables +This function collects applicable connection-local variables in +@code{connection-local-variables-alist} that is local to the buffer, +without applying them. Whether a connection-local variable is +applicable is specified by the remote identifier of a buffer, +evaluated by @code{(file-remote-p default-directory)}. +@end defun + +@defun hack-connection-local-variables-apply +This function looks for connection-local variables, and immediately +applies them in the current buffer. It is called per default for +every process-buffer related to a remote connection. For other remote +buffers, it could be called by any mode. +@end defun + +@defmac with-connection-local-classes classes &rest body +All connection-local variables, which are specified by a class in +@var{CLASSES}, are applied. An implicit binding of the classes to the +remote connection is enabled. + +After that, @var{BODY} is executed, and the connection-local variables +are unwound. Example: + +@example +@group +(connection-local-set-class-variables + 'remote-perl + '((perl-command-name . "/usr/local/bin/perl") + (perl-command-switch . "-e %s"))) +@end group + +@group +(with-connection-local-classes '(remote-perl) + do something useful) +@end group +@end example +@end defmac + +@defvar enable-connection-local-variables +If @code{nil}, connection-local variables are ignored. This variable +shall be changed temporarily only in special modes. +@end defvar + @node Variable Aliases @section Variable Aliases @cindex variable aliases diff --git a/etc/NEWS b/etc/NEWS index 03c4990..2e72fd5 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -223,6 +223,11 @@ These local variables will thus not vanish on setting a major mode. ** A second dir-local file (.dir-locals-2.el) is now accepted. See the variable 'dir-locals-file-2' for more information. ++++ +** Connection-local variables can be used to specify local variables +with a value depending on the connected remote server. For details, see +(info "(elisp)Connection Local Variables") + --- ** International domain names (IDNA) are now encoded via the new puny.el library, so that one can visit web sites with non-ASCII URLs. diff --git a/lisp/files-x.el b/lisp/files-x.el index 05ad7f5..212c936 100644 --- a/lisp/files-x.el +++ b/lisp/files-x.el @@ -543,6 +543,145 @@ from the MODE alist ignoring the input argument VALUE." (add-file-local-variable-prop-line (car elt) (cdr elt)))) +;;; connection-local variables. + +;;;###autoload +(defvar enable-connection-local-variables t + "Non-nil means enable use of connection-local variables.") + +(defvar connection-local-variables-alist nil + "Alist of connection-local variable settings in the current buffer. +Each element in this list has the form (VAR . VALUE), where VAR +is a connection-local variable (a symbol) and VALUE is its value. +The actual value in the buffer may differ from VALUE, if it is +changed by the user.") +(make-variable-buffer-local 'connection-local-variables-alist) +(setq ignored-local-variables + (cons 'connection-local-variables-alist ignored-local-variables)) + +(defvar connection-local-class-alist '() + "Alist mapping connection-local variable classes (symbols) to variable lists. +Each element in this list has the form (CLASS VARIABLES). +CLASS is the name of a variable class (a symbol). +VARIABLES is a list that declares connection-local variables for +CLASS. An element in VARIABLES is an alist whose elements are of +the form (VAR . VALUE).") + +(defvar connection-local-criteria-alist '() + "Alist mapping criteria to connection-local variable classes (symbols). +Each element in this list has the form (CRITERIA CLASSES). +CRITERIA is either a regular expression identifying a remote +server, or a function with one argument IDENTIFICATION, which +returns non-nil when a remote server shall apply CLASS'es +variables. If CRITERIA is nil, it always applies. +CLASSES is a list of variable classes (symbols).") + +(defsubst connection-local-get-classes (criteria &optional identification) + "Return the connection-local classes list for CRITERIA. +CRITERIA is either a regular expression identifying a remote +server, or a function with one argument IDENTIFICATION, which +returns non-nil when a remote server shall apply CLASS'es +variables. If CRITERIA is nil, it always applies. +If IDENTIFICATION is non-nil, CRITERIA must be nil, or match +IDENTIFICATION accordingly." + (and (cond ((null identification)) + ((not (stringp identification)) + (error "Wrong identification `%s'" identification)) + ((null criteria)) + ((stringp criteria) (string-match criteria identification)) + ((functionp criteria) (funcall criteria identification)) + (t "Wrong criteria `%s'" criteria)) + (cdr (assoc criteria connection-local-criteria-alist)))) + +;;;###autoload +(defun connection-local-set-classes (criteria &rest classes) + "Add CLASSES for remote servers. +CRITERIA is either a regular expression identifying a remote +server, or a function with one argument IDENTIFICATION, which +returns non-nil when a remote server shall apply CLASS'es +variables. If CRITERIA is nil, it always applies. +CLASSES are the names of a variable class (a symbol). + +When a connection to a remote server is opened and CRITERIA +matches to that server, the connection-local variables from CLASSES +are applied to the corresponding process buffer. The variables +for a class are defined using `connection-local-set-class-variables'." + (unless (or (null criteria) (stringp criteria) (functionp criteria)) + (error "Wrong criteria `%s'" criteria)) + (dolist (class classes) + (unless (assq class connection-local-class-alist) + (error "No such class `%s'" (symbol-name class)))) + (let ((slot (assoc criteria connection-local-criteria-alist))) + (if slot + (setcdr slot (delete-dups (append (cdr slot) classes))) + (setq connection-local-criteria-alist + (cons (cons criteria (delete-dups classes)) + connection-local-criteria-alist))))) + +(defsubst connection-local-get-class-variables (class) + "Return the connection-local variable list for CLASS." + (cdr (assq class connection-local-class-alist))) + +;;;###autoload +(defun connection-local-set-class-variables (class variables) + "Map the symbol CLASS to a list of variable settings. +VARIABLES is a list that declares connection-local variables for +the class. An element in VARIABLES is an alist whose elements +are of the form (VAR . VALUE). + +When a connection to a remote server is opened, the server's +classes are found. A server may be assigned a class using +`connection-local-set-class'. Then variables are set in the +server's process buffer according to the VARIABLES list of the +class. The list is processed in order." + (setf (alist-get class connection-local-class-alist) variables)) + +(defun hack-connection-local-variables () + "Read per-connection local variables for the current buffer. +Store the connection-local variables in `connection-local-variables-alist'. + +This does nothing if `enable-connection-local-variables' is nil." + (let ((identification (file-remote-p default-directory))) + (when (and enable-connection-local-variables identification) + ;; Loop over criteria. + (dolist (criteria (mapcar 'car connection-local-criteria-alist)) + ;; Filter classes which map identification. + (dolist (class (connection-local-get-classes criteria identification)) + ;; Loop over variables. + (dolist (variable (connection-local-get-class-variables class)) + (unless (assq (car variable) connection-local-variables-alist) + (push variable connection-local-variables-alist)))))))) + +;;;###autoload +(defun hack-connection-local-variables-apply () + "Apply connection-local variables identified by `default-directory'. +Other local variables, like file-local and dir-local variables, +will not be changed." + (hack-connection-local-variables) + (let ((file-local-variables-alist + (copy-tree connection-local-variables-alist))) + (hack-local-variables-apply))) + +;;;###autoload +(defmacro with-connection-local-classes (classes &rest body) + "Apply connection-local variables according to CLASSES in current buffer. +Execute BODY, and unwind connection local variables." + (declare (indent 1) (debug t)) + `(let ((enable-connection-local-variables t) + (old-buffer-local-variables (buffer-local-variables)) + connection-local-variables-alist connection-local-criteria-alist) + (apply 'connection-local-set-classes "" ,classes) + (hack-connection-local-variables-apply) + (unwind-protect + (progn ,@body) + ;; Cleanup. + (dolist (variable connection-local-variables-alist) + (let ((elt (assq (car variable) old-buffer-local-variables))) + (if elt + (set (make-local-variable (car elt)) (cdr elt)) + (kill-local-variable (car variable)))))))) + + (provide 'files-x) diff --git a/lisp/net/tramp-adb.el b/lisp/net/tramp-adb.el index 259b1cb..1aae0ec 100644 --- a/lisp/net/tramp-adb.el +++ b/lisp/net/tramp-adb.el @@ -1243,6 +1243,9 @@ connection if a previous connection has died for some reason." (read (current-buffer))) ":" 'omit)) + ;; Set connection-local variables. + (tramp-set-connection-local-variables vec) + ;; Mark it as connected. (tramp-set-connection-property p "connected" t))))))) diff --git a/lisp/net/tramp-gvfs.el b/lisp/net/tramp-gvfs.el index 637c2a7..a84097c 100644 --- a/lisp/net/tramp-gvfs.el +++ b/lisp/net/tramp-gvfs.el @@ -1723,6 +1723,9 @@ connection if a previous connection has died for some reason." (tramp-get-file-property vec "/" "fuse-mountpoint" "") "/") (tramp-error vec 'file-error "FUSE mount denied")) + ;; Set connection-local variables. + (tramp-set-connection-local-variables vec) + ;; Mark it as connected. (tramp-set-connection-property (tramp-get-connection-process vec) "connected" t)))) diff --git a/lisp/net/tramp-gw.el b/lisp/net/tramp-gw.el index b631072..8f8f107 100644 --- a/lisp/net/tramp-gw.el +++ b/lisp/net/tramp-gw.el @@ -333,5 +333,7 @@ password in password cache. This is done for the first try only." ;; * Provide descriptive Commentary. ;; ;; * Enable it for several gateway processes in parallel. +;; +;; * Use `url-https-proxy-connect' as of Emacs 26. ;;; tramp-gw.el ends here diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el index 6a190b0..1682b16 100644 --- a/lisp/net/tramp-sh.el +++ b/lisp/net/tramp-sh.el @@ -518,6 +518,7 @@ The string is used in `tramp-methods'.") ;; FreeBSD: /usr/bin:/bin:/usr/sbin:/sbin: - beware trailing ":"! ;; Darwin: /usr/bin:/bin:/usr/sbin:/sbin ;; IRIX64: /usr/bin +;; QNAP QTS: --- ;;;###tramp-autoload (defcustom tramp-remote-path '(tramp-default-remote-path "/bin" "/usr/bin" "/sbin" "/usr/sbin" @@ -4918,6 +4919,9 @@ connection if a previous connection has died for some reason." (setq options "" target-alist (cdr target-alist))) + ;; Set connection-local variables. + (tramp-set-connection-local-variables vec) + ;; Make initial shell settings. (tramp-open-connection-setup-interactive-shell p vec) diff --git a/lisp/net/tramp-smb.el b/lisp/net/tramp-smb.el index 0c8ecf4..7c60070 100644 --- a/lisp/net/tramp-smb.el +++ b/lisp/net/tramp-smb.el @@ -1916,6 +1916,9 @@ If ARGUMENT is non-nil, use it as argument for (tramp-set-connection-property p "smb-share" share) (tramp-set-connection-property p "chunksize" 1) + ;; Set connection-local variables. + (tramp-set-connection-local-variables vec) + ;; Mark it as connected. (tramp-set-connection-property p "connected" t)) diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el index c92c705..5d56fdf 100644 --- a/lisp/net/tramp.el +++ b/lisp/net/tramp.el @@ -1338,6 +1338,15 @@ In case a second asynchronous communication has been started, it is different from the default one." (get-process (tramp-get-connection-name vec))) +(defun tramp-set-connection-local-variables (vec) + "Set connection-local variables in the connection buffer used for VEC. +If connection-local variables are not supported by this Emacs +version, the function does nothing." + ;; `tramp-get-connection-buffer' sets proper `default-directory'." + (with-current-buffer (tramp-get-connection-buffer vec) + ;; `hack-connection-local-variables-apply' exists since Emacs 26.1. + (tramp-compat-funcall 'hack-connection-local-variables-apply))) + (defun tramp-debug-buffer-name (vec) "A name for the debug buffer for VEC." ;; We must use `tramp-file-name-real-host', because for gateway @@ -4325,13 +4334,6 @@ Only works for Bourne-like shells." ;; strange when doing zerop, we should kill the process and start ;; again. (Greg Stark) ;; -;; * Implement a general server-local-variable mechanism, as there are -;; probably other variables that need different values for different -;; servers too. The user could then configure a variable (such as -;; tramp-server-local-variable-alist) to define any such variables -;; that they need to, which would then be let bound as appropriate -;; in tramp functions. (Jason Rumney) -;; ;; * Make shadowfile.el grok Tramp filenames. (Bug#4526, Bug#4846) ;; ;; * I was wondering if it would be possible to use tramp even if I'm diff --git a/test/lisp/files-x-tests.el b/test/lisp/files-x-tests.el new file mode 100644 index 0000000..8f2c11d --- /dev/null +++ b/test/lisp/files-x-tests.el @@ -0,0 +1,297 @@ +;;; files-x-tests.el --- tests for files-x.el. + +;; Copyright (C) 2016 Free Software Foundation, Inc. + +;; Author: Michael Albinus + +;; This file is part of GNU Emacs. + +;; GNU Emacs 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. + +;; GNU Emacs 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 GNU Emacs. If not, see . + +;;; Code: + +(require 'ert) +(require 'files-x) + +(defvar files-x-test--criteria1 "my-user@my-remote-host") +(defvar files-x-test--criteria2 + (lambda (identification) + (string-match "another-user@my-remote-host" identification))) +(defvar files-x-test--criteria3 nil) + +(defvar files-x-test--variables1 + '((remote-shell-file-name . "/bin/bash") + (remote-shell-command-switch . "-c") + (remote-shell-interactive-switch . "-i") + (remote-shell-login-switch . "-l"))) +(defvar files-x-test--variables2 + '((remote-shell-file-name . "/bin/ksh"))) +(defvar files-x-test--variables3 + '((remote-null-device . "/dev/null"))) +(defvar files-x-test--variables4 + '((remote-null-device . "null"))) + +(ert-deftest files-x-test-connection-local-set-class-variables () + "Test setting connection-local class variables." + + ;; Declare (CLASS VARIABLES) objects. + (let (connection-local-class-alist connection-local-criteria-alist) + (connection-local-set-class-variables 'remote-bash files-x-test--variables1) + (should + (equal + (connection-local-get-class-variables 'remote-bash) + files-x-test--variables1)) + + (connection-local-set-class-variables 'remote-ksh files-x-test--variables2) + (should + (equal + (connection-local-get-class-variables 'remote-ksh) + files-x-test--variables2)) + + (connection-local-set-class-variables + 'remote-nullfile files-x-test--variables3) + (should + (equal + (connection-local-get-class-variables 'remote-nullfile) + files-x-test--variables3)) + + ;; A redefinition overwrites existing values. + (connection-local-set-class-variables + 'remote-nullfile files-x-test--variables4) + (should + (equal + (connection-local-get-class-variables 'remote-nullfile) + files-x-test--variables4)))) + +(ert-deftest files-x-test-connection-local-set-classes () + "Test setting connection-local classes." + + ;; Declare (CRITERIA CLASSES) objects. + (let (connection-local-class-alist connection-local-criteria-alist) + (connection-local-set-class-variables 'remote-bash files-x-test--variables1) + (connection-local-set-class-variables 'remote-ksh files-x-test--variables2) + (connection-local-set-class-variables + 'remote-nullfile files-x-test--variables3) + + (connection-local-set-classes + files-x-test--criteria1 'remote-bash 'remote-ksh) + (should + (equal + (connection-local-get-classes files-x-test--criteria1) + '(remote-bash remote-ksh))) + + (connection-local-set-classes files-x-test--criteria2 'remote-ksh) + (should + (equal + (connection-local-get-classes files-x-test--criteria2) + '(remote-ksh))) + ;; A further call adds classes. + (connection-local-set-classes files-x-test--criteria2 'remote-nullfile) + (should + (equal + (connection-local-get-classes files-x-test--criteria2) + '(remote-ksh remote-nullfile))) + ;; Adding existing classes doesn't matter. + (connection-local-set-classes + files-x-test--criteria2 'remote-bash 'remote-nullfile) + (should + (equal + (connection-local-get-classes files-x-test--criteria2) + '(remote-ksh remote-nullfile remote-bash))) + + ;; An empty variable list is accepted (but makes no sense). + (connection-local-set-classes files-x-test--criteria3) + (should-not (connection-local-get-classes files-x-test--criteria3)) + + ;; Using a nil criteria also works. Duplicate classes are trashed. + (connection-local-set-classes + files-x-test--criteria3 'remote-bash 'remote-ksh 'remote-ksh 'remote-bash) + (should + (equal + (connection-local-get-classes files-x-test--criteria3) + '(remote-bash remote-ksh))) + + ;; A criteria other than nil, regexp or lambda function is wrong. + (should-error (connection-local-set-classes 'dummy)))) + +(ert-deftest files-x-test-hack-connection-local-variables-apply () + "Test setting connection-local variables." + + (let (connection-local-class-alist connection-local-criteria-alist) + + (connection-local-set-class-variables 'remote-bash files-x-test--variables1) + (connection-local-set-class-variables 'remote-ksh files-x-test--variables2) + (connection-local-set-class-variables + 'remote-nullfile files-x-test--variables3) + + (connection-local-set-classes + files-x-test--criteria1 'remote-bash 'remote-ksh) + (connection-local-set-classes + files-x-test--criteria2 'remote-ksh 'remote-nullfile) + + ;; Apply the variables. + (with-temp-buffer + (let ((enable-connection-local-variables t) + (default-directory "/sudo:my-user@my-remote-host:")) + (should-not connection-local-variables-alist) + (should-not (local-variable-p 'remote-shell-file-name)) + (should-not (boundp 'remote-shell-file-name)) + (hack-connection-local-variables-apply) + ;; All connection-local variables are set. They apply in + ;; reverse order in `connection-local-variables-alist'. The + ;; settings from `remote-ksh' are not contained, because they + ;; declare same variables as in `remote-bash'. + (should + (equal connection-local-variables-alist + (nreverse (copy-tree files-x-test--variables1)))) + ;; The variables exist also as local variables. + (should (local-variable-p 'remote-shell-file-name)) + ;; The proper variable value is set. + (should + (string-equal (symbol-value 'remote-shell-file-name) "/bin/bash")))) + + ;; The second test case. + (with-temp-buffer + (let ((enable-connection-local-variables t) + (default-directory "/ssh:another-user@my-remote-host:")) + (should-not connection-local-variables-alist) + (should-not (local-variable-p 'remote-shell-file-name)) + (should-not (boundp 'remote-shell-file-name)) + (hack-connection-local-variables-apply) + ;; All connection-local variables are set. They apply in + ;; reverse order in `connection-local-variables-alist'. + (should + (equal connection-local-variables-alist + (append + (nreverse (copy-tree files-x-test--variables3)) + (nreverse (copy-tree files-x-test--variables2))))) + ;; The variables exist also as local variables. + (should (local-variable-p 'remote-shell-file-name)) + ;; The proper variable value is set. + (should + (string-equal (symbol-value 'remote-shell-file-name) "/bin/ksh")))) + + ;; The third test case. Both `files-x-test--criteria1' and + ;; `files-x-test--criteria3' apply, but there are no double + ;; entries. + (connection-local-set-classes + files-x-test--criteria3 'remote-bash 'remote-ksh) + (with-temp-buffer + (let ((enable-connection-local-variables t) + (default-directory "/sudo:my-user@my-remote-host:")) + (should-not connection-local-variables-alist) + (should-not (local-variable-p 'remote-shell-file-name)) + (should-not (boundp 'remote-shell-file-name)) + (hack-connection-local-variables-apply) + ;; All connection-local variables are set. They apply in + ;; reverse order in `connection-local-variables-alist'. The + ;; settings from `remote-ksh' are not contained, because they + ;; declare same variables as in `remote-bash'. + (should + (equal connection-local-variables-alist + (nreverse (copy-tree files-x-test--variables1)))) + ;; The variables exist also as local variables. + (should (local-variable-p 'remote-shell-file-name)) + ;; The proper variable value is set. + (should + (string-equal (symbol-value 'remote-shell-file-name) "/bin/bash")))) + + ;; When `enable-connection-local-variables' is nil, nothing happens. + (with-temp-buffer + (let ((enable-connection-local-variables nil) + (default-directory "/ssh:another-user@my-remote-host:")) + (should-not connection-local-variables-alist) + (should-not (local-variable-p 'remote-shell-file-name)) + (should-not (boundp 'remote-shell-file-name)) + (hack-connection-local-variables-apply) + (should-not connection-local-variables-alist) + (should-not (local-variable-p 'remote-shell-file-name)) + (should-not (boundp 'remote-shell-file-name)))))) + +(ert-deftest files-x-test-with-connection-local-classes () + "Test setting connection-local variables." + + (let (connection-local-class-alist connection-local-criteria-alist) + (connection-local-set-class-variables 'remote-bash files-x-test--variables1) + (connection-local-set-class-variables 'remote-ksh files-x-test--variables2) + (connection-local-set-class-variables + 'remote-nullfile files-x-test--variables3) + (connection-local-set-classes + files-x-test--criteria3 'remote-ksh 'remote-nullfile) + + (with-temp-buffer + (let ((enable-connection-local-variables t) + (default-directory "/sudo:my-user@my-remote-host:")) + (hack-connection-local-variables-apply) + + ;; All connection-local variables are set. They apply in + ;; reverse order in `connection-local-variables-alist'. + (should + (equal connection-local-variables-alist + (append + (nreverse (copy-tree files-x-test--variables3)) + (nreverse (copy-tree files-x-test--variables2))))) + ;; The variables exist also as local variables. + (should (local-variable-p 'remote-shell-file-name)) + (should (local-variable-p 'remote-null-device)) + ;; The proper variable values are set. + (should + (string-equal (symbol-value 'remote-shell-file-name) "/bin/ksh")) + (should + (string-equal (symbol-value 'remote-null-device) "/dev/null")) + + ;; A candidate connection-local variable is not bound yet. + (should-not (local-variable-p 'remote-shell-command-switch)) + + ;; Use the macro. + (with-connection-local-classes '(remote-bash remote-ksh) + ;; All connection-local variables are set. They apply in + ;; reverse order in `connection-local-variables-alist'. + ;; This variable keeps only the variables to be set inside + ;; the macro. + (should + (equal connection-local-variables-alist + (nreverse (copy-tree files-x-test--variables1)))) + ;; The variables exist also as local variables. + (should (local-variable-p 'remote-shell-file-name)) + (should (local-variable-p 'remote-shell-command-switch)) + ;; The proper variable values are set. The settings from + ;; `remote-bash' overwrite the same variables as in + ;; `remote-ksh'. + (should + (string-equal (symbol-value 'remote-shell-file-name) "/bin/bash")) + (should + (string-equal (symbol-value 'remote-shell-command-switch) "-c"))) + + ;; Everything is rewound. The old variable values are reset. + (should + (equal connection-local-variables-alist + (append + (nreverse (copy-tree files-x-test--variables3)) + (nreverse (copy-tree files-x-test--variables2))))) + ;; The variables exist also as local variables. + (should (local-variable-p 'remote-shell-file-name)) + (should (local-variable-p 'remote-null-device)) + ;; The proper variable values are set. The settings from + ;; `remote-ksh' are back. + (should + (string-equal (symbol-value 'remote-shell-file-name) "/bin/ksh")) + (should + (string-equal (symbol-value 'remote-null-device) "/dev/null")) + + ;; The variable set temporarily is not unbound, again. + (should-not (local-variable-p 'remote-shell-command-switch)))))) + +(provide 'files-x-tests) +;;; files-x-tests.el ends here