Setting per-project indent variables in emacs - emacs

My emacs is set to use 2 spaces for indentation globally:
(setq-default indent-tabs-mode nil)
(setq tab-width 2)
(setq js-indent-level 2)
(setq css-indent-offset 2)
But I would like to contribute to a web project (html, css and js mostly) which uses 4 spaces for indentation. So I am trying to set up a .dir-locals.el file in the project directory. The file has the following settings (added with the add-dir-local-variable command):
((nil . ((tab-width . 4)
(js-indent-level . 4)))
;;; Directory Local Variables
;;; See Info node `(emacs) Directory Variables' for more information.
((js-mode
(tab-width . 4)))
;;; Directory Local Variables
;;; See Info node `(emacs) Directory Variables' for more information.
((js-mode
(js-indent-level . 4)))
;;; Directory Local Variables
;;; See Info node `(emacs) Directory Variables' for more information.
((html-mode
(tab-width . 4)))
But these settings don’t take effect. When I open a .js or .html file in a project subdirectory, pressing tab makes a 2-space indent.
What am I doing wrong?

For starters your .dir-locals.el data is unbalanced (M-x check-parens).
I'm not sure how that would have happened, but if you can get Emacs to do it, then you should M-x report-emacs-bug. I'm assuming it was from manual editing.
I'm not sure whether the multiple js-mode items is a valid thing to do. Maybe that's fine, but it seems unusual. (Possibly Emacs is confused by the unbalanced parens, though.)
Here's your file re-written to use the more common (or at least the documented) dotted-pair notation:
((nil . ((tab-width . 4)
(js-indent-level . 4)))
(js-mode . ((tab-width . 4)
(js-indent-level . 4)))
(html-mode . ((tab-width . 4))))
Please note that (for this specific data) you don't need the js-mode and html-mode entries, because they are duplicating the default values for the nil mode entry.
Edit: Experimentally, add-dir-local-variable seems to behave as expected once the file is in a valid state.
It prefers creating the more compact list notation where possible -- which is fine; they're equivalent -- but it's useful to be aware of the formatting differences.
See C-hig (elisp) Dotted Pair Notation RET

Related

Emacs. Spell check "on fly" for 2 languages

Windows 7, Emacs 25.1
I need to spell check "on fly" for my custom text (e.g. to emphasize the incorrect words). But I write text in two languages: English and Russian. And I want easy to switch between spell checking for 2 languages.
What is the best emacs package for this? Thanks.
You want this: guess_language.el
(use-package guess-language ; Automatically detect language for Flyspell
:ensure t
:defer t
:init (add-hook 'text-mode-hook #'guess-language-mode)
:config
(setq guess-language-langcodes '((en . ("en_GB" "English"))
(it . ("it_IT" "Italian")))
guess-language-languages '(en it)
guess-language-min-paragraph-length 45)
:diminish guess-language-mode)
Alternatively if you just want to cycle through them:
(defvar mu-languages-ring nil "Languages ring for Ispell")
(let ((languages '("en_GB" "it_IT")))
(validate-setq mu-languages-ring (make-ring (length languages)))
(dolist (elem languages) (ring-insert mu-languages-ring elem)))
(defun mu-cycle-ispell-languages ()
(interactive)
(let ((language (ring-ref mu-languages-ring -1)))
(ring-insert mu-languages-ring language)
(ispell-change-dictionary language)))
These should work with FlySpell
I had a similar problem, the solution I found manages two or more languages at the same time without using guess_language package. This solution is based on Hunspell spelling checker.
SYSTEM:
Windows 7 SP1, GNU Emacs 26.1
First, perform a Ispell/Hunspell configuration after Hunspell installation. Insert the next code in the .emacs file, usually located within C:/Users/Account.
;; START BLOCK1 <-- Ispell/Hunspell setting
;; e.g., "C:/Hunspell/bin/hunspell.exe"
(setq-default ispell-program-name "hunspell.exe FULL PATH")
(setq-default ispell-extra-args '("--sug-mode=ultra"))
;; Set "DICTDIR" variable, e.g., "C:/Hunspell/share/hunspell"
(setenv "DICTDIR" "hunspell DICTIONARY PATH")
;; Uncomment next line to set English or another dictionary
;; (setq ispell-dictionary "en_US")
;; Automatically enable flyspell-mode in text-mode
(setq text-mode-hook '(lambda() (flyspell-mode t) ))
(require 'ispell)
;; END BLOCK1 <-- Ispell/Hunspell setting
This code is based on the spelling configuration section of another discussion, see M Parashar - Load Theme. The block code 1 works for the default dictionary, which can be changed uncommenting the line with the ispell-dictionary variable. This code works perfectly for me.
The second code block enable us to use multiple dictionaries, is based on AM Lafon - Multi Spell Checking. For me, this code block works only next of code block 1.
;;START BLOCK2<-- Multiple dictionaries. Only works with BLOCK1
(with-eval-after-load "ispell"
;; Configure `LANG`, otherwise ispell.el cannot find a 'default
;; dictionary' even though multiple dictionaries will be configured
;; in next line.
(setenv "LANG" "es_ES")
;; English/spanish configuration.
(setq ispell-dictionary "en_US,es_ES")
;; ispell-set-spellchecker-params has to be called
;; before ispell-hunspell-add-multi-dic will work
(ispell-set-spellchecker-params)
(ispell-hunspell-add-multi-dic "en_US,es_ES")
;; For saving words to the personal dictionary, don't infer it from
;; the locale, otherwise it would save to ~/.hunspell_de_DE.
(setq ispell-personal-dictionary "~/.hunspell_personal"))
;; The personal dictionary file has to exist, otherwise hunspell will
;; silently not use it.
(unless (file-exists-p ispell-personal-dictionary)
(write-region "" nil ispell-personal-dictionary nil 0))
;;END BLOCK2<-- Multiple dictionaries. Only works with BLOCK1
These two code blocks enable the spell checking for the english/spanish languages at the same time. More languages can be added to the checking system expanding the "en_US,es_ES" strings with the appropriate dictionary names. I used that ones located in the Share/Hunspell directory. There is no keybinding to change between languages and no per file dictionary assignation at the beginning of files, like this:
# -\*- ispell-dictionary: "castellano8" -\*-.
A context menu is displayed when clicking the middle mouse button over the misspelled word, an option is the Save Word entry. These words will be saved using the variable ispell-personal-dictionary in the new file called .hunspell_personal, located on the usual path.
The inclusion of the two code blocks gave the expected results. Just including the second block of code threw the error 'wrong-type-argument stringp nil'.

Emacs: Is it possible to set specific indentation settings for specific desktops in desktop+?

I have to work on a lot of different projects that all tend to use different indentation amounts (usually just 2 and 4 spaces) for js, php, etc. I manage project sessions using emacs-desktop.
Thank you so much!
Rather than doing this via emacs-desktop, I suggest using Per-directory Local Variables. These are designed for exactly this purpose.
For example, here is the .dir-locals.el that I use for hacking on firefox:
(
;; Generic settings.
(nil .
;; See C-h f bug-reference-prog-mode, e.g, for using this.
((bug-reference-url-format . "https://bugzilla.mozilla.org/show_bug.cgi?id=%s")
(bug-reference-bug-regexp . "\\([Bb]ug ?#?\\|[Pp]atch ?#\\|RFE ?#\\|PR [a-z-+]+/\\)\\([0-9]+\\(?:#[0-9]+\\)?\\)")))
;; The built-in javascript mode.
(js-mode .
((indent-tabs-mode . nil)
(js-indent-level . 2)))
(c++-mode .
((indent-tabs-mode . nil)
(c-basic-offset . 2)))
(idl-mode .
((indent-tabs-mode . nil)
(c-basic-offset . 2)))
)
This customizes the indentation for a few programming modes, disables indent-tabs-mode where it matters, and arranges to buttonize bug references in the firefox source.

emacs: open all .txt files in a specific directory in a specific major mode

EDIT: It turns out that the second edit to my .emacs file actually works. (See the comments below this entry.)
I tried a couple of addition to the .emacs to make all txt files opened in emacs use orgmode. They did not work. How can I make it happen?
;;SET EMACS AS DEFAULT MAJOR MODE TO FOR ALL FILES WITH AN UNSPECIFIED MODE
(setq default-major-mode 'org-mode)
;;OPEN ALL TXT FILES IN ORGMODE
(add-to-list 'auto-mode-alist '("\\.txt$" . org-mode))
Additionally:
It would be even better to open only txt files in a certain directory orgmode. Any hint as to how that could be done would also be appreciated.
Another way to do this is using directory-local variables. This is nice because you can put a file in any directory where you want this behavior to engage, and it works recursively in any subdirectories.
Create a file called .dir-locals.el in the desired directory.
Here are the contents:
((nil (eval . (if (string-match ".txt$" (buffer-file-name))(org-mode)))))
Read this like so: for any major-mode (nil), evaluate the following form:
(if .... (org-mode))
The regex in auto-mode-alist could be something more complex, like "^/path/to/.*\\.txt$"
You can implement a hook which verifies the file directory and modifies the buffer mode:
(add-hook 'find-file-hooks
(lambda ()
(let ((file (buffer-file-name)))
(when (and file (equal (file-name-directory file) "c:/temp/"))
(org-mode)))))
As an alternative you can add the mode line in the beginning of your text file. In this case emacs will set the specified mode.
; -*- mode: org;-*-
* header 1
** header 2
I glued together some code from Oleg Pavliv's answer here, and from yibe's at elisp - File extension hook in Emacs - Stack Overflow
(defun use-org-mode-for-dot-txt-files-in-owncloud ()
(when (and (string-match owncloud buffer-file-name)
(string-match "\\.txt\\'" buffer-file-name))
(org-mode)))
(add-hook 'find-file-hook 'use-org-mode-for-dot-txt-files-in-owncloud)
This way, though ownCloud Web and phone apps are currently friendly only with .txt files, from my PC I can use Emacs' Org-mode for them.
(If I set all .txt files to use Org-mode, it breaks todotxt-mode.)
(Note that owncloud is a string variable equal to my ownCloud path.)

Emacs: Set tab indent for just one file on the fly

I work on an open source project where the creator sets his tab-indents to 2 spaces.
I'd like to just enable it on the fly for the one file I work on and not other files of the same type. There must be something like M-x set-tab-indent. It is a JavaScript file ending in .js.
I know I can use:
(setq-default tab-width int)
inside my .emacs file, but I rather just call an M-x command to set it and forget it during my duration of working on this file. I tried M-x apropos and Google but couldn't find the specific command.
Thanks.
You can make the variable js-indent-level local to the buffer using:
M-x make-variable-buffer-local <RET> js-indent-level <RET>
Then you can set that variable in the buffer using:
M-x set-variable <RET> js-indent-level <RET> 2
The easiest way to do this for a single buffer is to use M-x set-variable.
Type M-x set-variable and press enter
When prompted for the variable to set, set tab-width then press enter
You'll be prompted with the line Set tab-width (buffer-local) to value:.
Put the value you want, then hit enter
The buffer should instantly be updated with the new value.
You could also use file local variables to automate omrib's solution for that one file, by adding this to it:
// Local Variables:
// js-indent-level: 2
// indent-tabs-mode: nil
// End:
Create a file ".dir-locals.el" in the project's directory and fill it like this:
((nil . ((tab-width . 2))))
This will take care of setting tab-width automatically and you don't have to modify the actual file (which is likely version-controlled.)
See the manual for more information about the format. I believe this requires Emacs 23.
As indicated by others, one issue with the File Local Variables approach is that you need to modify the file, and that's not ideal if you need to keep those declarations out of version control.
If you want the variables to apply to all files under a given directory, then Directory Local Variables is obviously the way to go, and you can implement that with either a .dir-locals.el file, or by calling (dir-locals-set-directory-class):
http://www.emacswiki.org/emacs/DirectoryVariables
http://www.gnu.org/software/emacs/manual/html_node/emacs/Directory-Variables.html
I prefer the directory class approach myself, and I was thinking that it's a shame that there isn't an analogous approach for file local variables, but I found that the directory class code actually works perfectly with files, and the only issue is that dir-locals-set-directory-class calls file-name-as-directory on its argument, which prevents it from being matched, due to the trailing slash.
The following therefore is a way to configure directory local variables for a single file, without modifying the file itself, or affecting other files under the same parent directory.
(defun my-file-locals-set-directory-class (file class &optional mtime)
"Enable 'directory local' classes for individual files,
by allowing non-directories in `dir-locals-directory-cache'.
Adapted from `dir-locals-set-directory-class'."
(setq file (expand-file-name file))
(unless (assq class dir-locals-class-alist)
(error "No such class `%s'" (symbol-name class)))
(push (list file class mtime) dir-locals-directory-cache))
(dir-locals-set-class-variables
'my-javascript-class
'((nil . ((js-indent-level . 2)
(indent-tabs-mode . nil)))))
(my-file-locals-set-directory-class
"path/to/the/file.js" 'my-javascript-class)
I use a snippet of code in my init.el that tries to auto-detect files that use 2-space indents, and switch Emacs's indentation for that file to 2 spaces when it sees such files:
(add-hook 'js-mode-hook
(lambda ()
(when (string-match-p "^ [A-Za-z]" (buffer-string))
(make-variable-buffer-local 'js-indent-level)
(set-variable 'js-indent-level 2))))

Emacs modeline at the end of file in one line

I am working on a project where some people use vi, some use emacs and some others (including gedit). The most simple yet global way (although not perfect) to enforce (at least visual) style was to add the following lines to the end of each file:
...
return 0;
}
// Editor modelines - generated by http://www.wireshark.org/tools/modelines.html
// Local variables:
// c-basic-offset: 4
// tab-width: 4
// indent-tabs-mode: t
// truncate-lines: 1
// End:
// vim:set ft=cpp ts=4 sw=4 sts=4 nowrap: cindent:
the question is: how can I convert the emacs portion in a "one-line" code (as vim can)? and yet keep it at the end of the source file (not at the top).
(Probably this can be recasted as Lisp question but I am not familiar with it)
Directory Local Variables are probably a better approach.
http://www.emacswiki.org/emacs/DirectoryVariables
http://www.gnu.org/software/emacs/manual/html_node/emacs/Directory-Variables.html
The single .dir-locals.el file will be processed by everyone, and no need for file local variables at all.
vim may well have a similar mechanism?
You can use the eval: declaration, but Emacs will ask you to confirm that it is safe to evaluate. If you tell Emacs to accept it permanently, it won't ask about that expression again (it stores it in safe-local-variable-values in the custom-set-variables section of your init file).
;;; Local Variables:
;;; eval:(setq c-basic-offset 4 tab-width 4 indent-tabs-mode t truncate-lines 1)
;;; End:
You can wrap multiple expressions in progn:
;;; Local Variables:
;;; eval:(progn (setq c-basic-offset 4) (message "hello"))
;;; End:
Or use any other constructs (I don't think there are any restrictions).
You would need to use the // Local Variables: and // End:. The rest can be made into one line as in // eval: (setq c-basic-offset 4 tab-width 4 indent-tabs-mode t truncate-lines 1).
Looks like you might be SOL:
Specifying File Variables: http://www.gnu.org/software/emacs/manual/html_node/emacs/Specifying-File-Variables.html
Variables in Emacs:
http://www.gnu.org/software/emacs/manual/html_node/emacs/Variables.html#Variables
Unless you use Phils's eval style.
(setq c-basic-offset 4 tab-width 4 indent-tabs-mode t truncate-lines 1) add this to your .emacs. If you wish to do this for specific file types you can always use the add-hook call, such as (add-hook 'c-mode-common-hook 'your-func-here) where your-func-here could be a function that simply sets those variables.
Refer to phils method of using Local Variables and eval to accomplish this with the first line of code given above. Sorry I didn't quite understand that this was only for a single file or very few files.
I'm going to turn the question around? Do you really need any file-local variables? If you use the same style throughout all source files, it might be better to define a C indentation setup and distribute this among all developers.
(defconst my-c-style
'((c-basic-offset . 2)
(c-offsets-alist
. ((substatement-open . 0)
(statement-case-open . +)
(inline-open . 0)
(arglist-cont-nonempty . (c-indent-operator-lineup-arglist-operators
c-lineup-arglist)))))
"My indentation style")
(defun my-c-mode-common-hook ()
(interactive)
(c-add-style "my" my-c-style t))
(add-hook 'c-mode-common-hook 'my-c-mode-common-hook)