Executando spacemacs ao lado de emacs regulares: como manter um arquivo .emacs.d separado

32

Eu gostaria de experimentar o spacemacs. Mas ainda não quero mudar da minha configuração regular do emacs, portanto, gostaria que a configuração que está atualmente no meu .emacs.desteja em um diretório e a configuração equivalente para o spacemacs esteja em outro diretório. Não me importo com o nome de nenhum diretório.

Isso é possível, sem chroots / LD_PRELOAD / outros truques desse tipo? Como eu posso fazer isso?

Croad Langshan
fonte
2
Veja também a resposta de Dan para uma pergunta semelhante que tive sobre como configurar um cronômetro com opções quando o Emacs é iniciado: emacs.stackexchange.com/questions/3588/… Desde então, tenho usado uma pequena variação dessa resposta.
lawlist
1
Na categoria “outros truques”, talvez você possa criar um link simbólico spacemacsapontando para o executável do emacs e usar o valor de (car command-line-args)para decidir qual arquivo init será executado. Isso pressupõe, é claro, que você esteja executando em um sistema unix diferente do OS X. (A maneira como os pacotes de aplicativos funcionam no OS X dificulta a execução desse truque.)
Harald Hanche-Olsen
1
Veja outra abordagem aqui: emacs.stackexchange.com/q/4253/780
glucas 28/16
2
Acabei de voltar para dizer, cerca de 18 meses depois, essa ainda é a razão de eu não ter aprendido o SpaceMacs. Tive alguns problemas com a resposta aceita, apenas tentei novamente, ainda é verdade. Depois de adicionar a camada organizacional, obtive "A definição da função do símbolo é nula: loop" agora. Não sei que isso faz parte da causa, mas esse é exatamente o problema: para um projeto polido de "baterias incluídas", parece estranho ter que juntar algo apenas para iniciá-lo, e então me pergunto se minha configuração é suportada? Talvez injusto, mas isso me faz perder a confiança. Talvez em outros 18 meses ele vai ser corrigido ...
Croad Langshan

Respostas:

20

Uma opção é especificar qual configuração você deseja carregar em um ~/.emacsarquivo. Quando o Emacs inicia, ele procura esse arquivo antes de procurar ~/.emacs.d/. Para mais detalhes, você pode ler sobre o arquivo Init no manual do Emacs.

Por exemplo, você pode criar um ~/.spacemacs.de manter o seu existente ~/.emacs.dcomo ele é. Em seguida, crie um ~/.emacspara carregar o que você deseja usar:

(setq use-spacemacs t)   ; or nil 

(when use-spacemacs
  (setq user-emacs-directory "~/.spacemacs.d/"))   ; defaults to ~/.emacs.d/

(load (expand-file-name "init.el" user-emacs-directory))

Se você quiser, pode encontrar maneiras de mudar as configurações sem modificar o arquivo .emacs. Por exemplo, faça com que o seu .emacs verifique alguma variável de ambiente que você definiu no shell ou em um script usado para iniciar o spacemacs:

(setq use-spacemacs (getenv "USE_SPACEMACS"))
glucas
fonte
1
Certamente, deve haver uma maneira de dentro do elisp para saber se você está executando o spacemacs ou não? Por exemplo, marcando (com fboundp) uma função ou comando exclusivo do spacemacs?
Harald Hanche-Olsen
2
Claro, mas essa não era a questão que eu entendi. O Spacemacs é apenas uma configuração do emacs, e o OP quer saber como manter mais de um diretório de configuração do emacs independente.
glucas
1
@ HaraldHanche-Olsen que também me surpreendeu quando o baixei, mas quando pensei nisso, fez total sentido. Acho que a razão pela qual esperamos isso é que, para a maioria dos sistemas, para criar um 'produto' polido como o spacemacs, parece necessário rodar uma linguagem de sistemas de nível inferior - mas no emacs há muita extensibilidade (obrigado elisp) que isso não é necessário.
Croad Langshan
1
Eu aceitei isso, mas realmente não tentei. Agora que tenho, ele não funciona exatamente como está: Erro no arquivo: Não é possível abrir o arquivo de carregamento, /home/me/.emacs.d/core/core-load-paths.el - eu precisava (setq user-emacs-directory "~/.spacemacs.d/")fazê-lo trabalho (em um prognno ramo spacemacs do seu condicional). Você pode adicionar isso à sua resposta para que eu possa aceitá-la novamente?
Croad Langshan
2
@glucas Estou no win10, por algum motivo o HOME foi atribuído a c: / users / nate. Removida a variável ambiental e tudo funcionou bem.
Nathaniel Saxe
12

Como há mais o que fazer no init do que apenas carregar um arquivo e, por outro lado, desvincular .emacs.dou alterar HOMEalterações no meu ambiente de tempo de execução, optei por uma variante do que o @glucas havia proposto. Usei o código startup.ele adicionei o patch do # 15539 para usar uma variável de ambiente para alternar entre diferentes diretórios init. Se nenhum for fornecido, o padrão é usado.

Houve um problema com o spacemacs: asyncnão sabe sobre o diretório init alterado e, portanto, não consegue encontrar alguns arquivos necessários. Mas isso foi resolvido recentemente no spacemacs: Erro ao usar um diretório de configuração diferente de .emacs.d · Edição nº 3390

Então, aqui está o meu ~/.emacsque deve se comportar como o código init original, mas com o diretório init configurável:

;;; .emacs --- let the user choose the emacs environment to use

;;; Commentary:
;;; This code mimics the behaviour of `startup.el' to let the
;;; usage of the custom init directory behave just like the
;;; one and only "~/.emacs.d".
;;;
;;; By setting the environment variable `EMACS_USER_DIRECTORY'
;;; the user-emacs-directory can be chosen and if there is an
;;; `init.el' the configuration from that directory will be used.
;;; If the environment variable is not set or there is no `init.el'
;;; the default configuration directory `~/.emacs.d/' will be used.
;;;
;;; The variable `server-name' will be set to the name of the directory
;;; chosen as start path.  So if the server will be started, it can be
;;; reached with 'emacsclient -s servername'.
;;;
;;; This now works with a current version of spacemacs but does not
;;; work with `async-start' in general, if the code executed with `async'
;;; uses `user-init-dir' or makes other assumptions about the emacs
;;; start-directory.

;;; Code:
(let* ((user-init-dir-default
    (file-name-as-directory (concat "~" init-file-user "/.emacs.d")))
       (user-init-dir
    (file-name-as-directory (or (getenv "EMACS_USER_DIRECTORY")
                    user-init-dir-default)))
       (user-init-file-1
    (expand-file-name "init" user-init-dir)))
  (setq user-emacs-directory user-init-dir)
  (with-eval-after-load "server"
    (setq server-name
      (let ((server--name (file-name-nondirectory
                   (directory-file-name user-emacs-directory))))
        (if (equal server--name ".emacs.d")
        "server"
          server--name))))
  (setq user-init-file t)
  (load user-init-file-1 t t)
  (when (eq user-init-file t)
    (setq user-emacs-directory user-init-dir-default)
    (load (expand-file-name "init" user-init-dir-default) t t)))

(provide '.emacs)
;;; .emacs ends here

Há também uma boa adição que o faz funcionar como um daemon sem esforço extra: o nome do servidor será definido como o nome do diretório init. Então agora você pode iniciar um segundo daemon do emacs com um spacemacs de baunilha

EMACS_USER_DIRECTORY=~/.emacsenv.d/spacemacs emacs --daemon

e ainda use o emacsclient

emacsclient -s spacemacs -c -e '(message "Hello spacemacs")'

Meu caso de usuário é muito simples e estou surpreso por ser o único: tenho um daemon do emacs sempre em execução e o uso no gui e no console (com ssh por exemplo). Neste emacs, preparo toda a minha documentação e registro de trabalho, para que esteja lá o tempo todo. Mas então eu quero experimentar o spacemacs ou um dos outros pacotes de distribuição e até configurá-lo, até que eu possa aposentar minha configuração atual ou usar algumas das idéias inteligentes. E, como outros, eu queria criar uma configuração básica simples para meus colegas de trabalho - e documentá-la com o modo org na minha instância em execução.

Como o único problema que conheço é asynce ele não conhece o diretório init alterado, penso na melhor maneira de adicionar algumas configurações às asyncvariáveis ​​que devem ser injetadas por padrão, para que não seja necessário corrigir todos os invocações async-startexatamente como os spacemacs haviam feito.

Uwe Koloska
fonte
Isso é realmente adorável e funcionou lindamente ... até que eu precisei usar async. :-( Como já faz alguns meses desde que você postou, você tem uma solução alternativa?
Trey
Infelizmente não - mas para o spacemacs é fixo e para o async geral, não tenho muita certeza se deve haver alguma alteração, porque async-startinicia o emacs sem nada e se você quiser usar alguma variável, precisará passar. Mas com certeza seja agradável e conveniente, se o assíncrono puder ser configurado com uma lista de variáveis, que serão usadas em todas as chamadas de async-start.
Uwe Koloska 08/09/16
1
Com essa abordagem, pode haver outras variáveis ​​que são inicializadas no diretório user-emacs-padrão antes do carregamento do seu .emacs. Por exemplo, eu precisava adicionar (setq custom-theme-directory user-emacs-directory)aqui.
glucas
1
Não sei onde essa variável está definida, porque quando a examino dentro de um testenv mínimo, recebo: Seu valor é "~ / .emacs.d /". O valor original era "~ / .emacsenv.d / init-test /" Portanto, ele tem o valor correto, mas foi substituído.
Uwe Koloska
1
Acabei usando essa resposta muito tempo depois de fazer a pergunta. Não mudei a resposta aceita porque é muito longa e porque não prestei muita atenção à implementação! Esta resposta tem sido muito útil para mim, no entanto.
Croad Langshan
5

É explicado aqui e há um PR em andamento para adicioná-lo à documentação:

mkdir ~/spacemacs
git clone [email protected]:syl20bnr/spacemacs.git ~/spacemacs/.emacs.d
HOME=~/spacemacs emacs```
StreakyCobra
fonte
6
Sim, às vezes mudo HOME para experimentar uma configuração alternativa. A desvantagem é que o HOME é usado para outras coisas que você pode preferir não afetar.
glucas
3

Ele já foi respondido e aceito, mas se você quiser experimentar novas maneiras de fazer as coisas da maneira reversível (além das configurações do emacs), recomendo que você gaste meia hora se familiarizando com o GNU Stow. É uma espécie de ln -sesteróides, e pode haver várias abordagens para usá-lo. Você pode ter toda a configuração em um subdiretório (incluindo configurações offlineimap, configurações do emacs etc.) - isso seria uma abordagem baseada no ambiente - ou ter um subdiretório separado para cada aplicativo que você possui. Doce esquizofrenia.

Por exemplo, lista relacionada ao emacs do meu ~ / Stow:

-> % ls ~/Stow | grep emacs
emacs 
emacs_from_scratch
spacemacs
hoodoo@T450s 2:46 [~]

Há uma configuração inicial que eu consegui usar, uma configuração de 'eu fico com os padrões' e uma 'eu vou rolar sozinha'. Posso ativar e desativar cada uma delas e sempre tê-las disponíveis. Cada subdiretório pode ter uma árvore inteira em relação ao meu ~ / e é bastante útil misturar e combinar.

Roman Grazhdan
fonte
Eu uso a arrumação já que acontece. Mas como você o usa para isso? Você está apenas 'escaneando dinamicamente' seu .emacs.d ligando / desativando o que deseja usar, usando o stow? Você já correu os dois ao mesmo tempo? Nesse caso, acho que os dois emacses acham que "possuem" .emacs.d. Gostaria de saber se isso pode causar algumas esquisitices com coisas que salvam o estado lá, como eu não sei dizer recentes, salvamentos históricos, salvamentos automáticos etc. especialmente quando as duas cópias do emacs estão sendo executadas com configurações radicalmente diferentes?
Croad Langshan
Não, apenas mudei as configurações conforme necessário.
Roman Grazhdan
2

Eu verifiquei o patch que @Uwe Koloska usou. Não foi incluído no ramo principal. Concordo um pouco, acho que o problema deve ser resolvido fora do emacs usando o shell e deixando o emacs sem saber nada sobre isso.

Talvez esse recurso seja mais lógico da perspectiva do usuário, o uso de um sinalizador seria menos complicado para alguns usuários.

No meu caso de uso, quero manter minha instalação do Emacs e do Spacemacs para que minha variação das duas soluções acima funcione dessa maneira.

script de shell

Primeiro de tudo o script para iniciar o spacemacs:

#!/bin/sh

export EMACS_USER_DIR=~/spacemacs/emacs.d

exec emacs "$@"

Este script é chamado spacemacse está instalado na /usr/local/binpasta.

arquivo .emacs

Então eu preciso de um .emacsarquivo na minha pasta pessoal que trate corretamente a variável de ambiente EMACS_USER_DIR.

(defvar user-custom-dir (getenv "EMACS_USER_DIR"))

(when (/= (length user-custom-dir) 0)
  (setq user-emacs-directory (file-name-as-directory user-custom-dir)))

(load (expand-file-name "init.el" user-emacs-directory))

Eu não sou experiente com o elisp, então vim à tona, pessoas mais experientes provavelmente poderiam criar algo melhor. Mas ei, isso funciona.

Eye-candy

Então porque não adicionar um ícone:

ícone

[Desktop Entry]
Name=Spacemacs
GenericName=Text Editor
Comment=Edit text
MimeType=text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-c;text/x-c++;
Exec=spacemacs %F
Icon=/home/marcs/.icons/spacemacs.svg
Type=Application
Terminal=false
Categories=Development;TextEditor;
StartupWMClass=Emacs
Keywords=Text;Editor;
Marcs
fonte
3
Seu shell script deve usar exec emacs "$@".
Uwe Koloska 03/10/19
Sim, obrigado pela dica, apenas corrigida.
Marcs