Re: [O] Feature request: Maintaining multiple init files with one org file

2018-07-30 Thread Diego Zamboni
Hi Sven,

Personally, I do not like the idea of having to generate the config files
on every host - I prefer to tangle once, on my main machine, and then
distribute (via git) both the org source and the tangled result to all my
machines. This results in much lower maintenance effort - otherwise I would
need to login to each machine, open Emacs there, and tangle the file (or
automate the process, but still, more work than doing it once). This means
that the logic still needs to be present in the resulting file, but it
doesn't mean the org source needs to be less readable. What I do is use
noweb mode selectively, to indicate the corresponding sections. I use this
for the OS-specific configuration in my Emacs file:
https://github.com/zzamboni/dot-emacs/blob/master/init.org#system-specific-configuration
.

In short, the top-level block includes the necessary logic, plus the
corresponding sections in noweb-style references (the :noweb no-export
makes it so that the tags get expanded only when tangling and not when
exporting, which makes my rendered config files more readable, see the
links below):


#+begin_src emacs-lisp :noweb no-export
  (cond ((eq system-type 'darwin)
 <>
 )
((eq system-type 'windows-nt)
 <>
 )
((eq system-type 'gnu/linux)
 <>
 ))
#+end_src


Then, each subsection sets the corresponding section-level properties, so
that they don't have to be specified in each block - then all the blocks
within that section will be automatically inserted in the corresponding
"section" of the cond statement above. For example:

** Mac
:PROPERTIES:
:header-args:emacs-lisp: :tangle no :noweb-ref Mac settings
:END:

First, we set the key modifiers correctly to my preferences: Make Command
(⌘) act as Meta, Option as Alt, right-Option as Super

#+begin_src emacs-lisp
  (customize-set-variable 'mac-command-modifier 'meta)
  (customize-set-variable 'mac-option-modifier 'alt)
  (customize-set-variable 'mac-right-option-modifier 'super)
#+end_src


You can see the real file here:
https://github.com/zzamboni/dot-emacs/blob/master/init.org#system-specific-configuration,
or in a nicer rendering in my blog:
https://zzamboni.org/post/my-emacs-configuration-with-commentary/#system-specific-configuration

Hope this helps - not exactly what you asked, but maybe a useful
alternative?

Best,
--Diego


On Sat, Jul 28, 2018 at 11:25 AM, Sven Bretfeld 
wrote:

> Hi
>
> I don't know how you guys maintain init files for different hosts. I
> have one org-file with the header:
>
> #+PROPERTY: header-args :tangle ~/.emacs
>
> The file is synced to all my machines and produces the local init files
> on each. Most configurations are shared, but some are host-specific
> (e.g. font size).
>
> Sadly export filtering does not work with the tangle function. It would
> be nice to be able to do something like:
>
> ,
> | * Default Frame
> | ** Office Computer:OFFICE:
> | #+begin_src emacs-lisp
> | (setq default-frame-alist '(
> | (font . "-PfEd-DejaVu Sans Mono-normal-normal-normal-*-
> 26-*-*-*-m-0-iso10646-1")
> | (width . 102)
> | (height . 41))
> | #+end_src
> |
> | ** Computer at home   :HOME:
> | #+begin_src emacs-lisp
> | (setq default-frame-alist '(
> | (font . "-PfEd-DejaVu Sans Mono-normal-normal-normal-*-
> 18-*-*-*-m-0-iso10646-1")
> | (width . 150)
> | (height . 50))
> | #+end_src
> |
> | ** Laptop :LAPTOP:
> | #+begin_src emacs-lisp
> | (setq default-frame-alist '(
> | (font . "-PfEd-DejaVu Sans Mono-normal-normal-normal-*-
> 12-*-*-*-m-0-iso10646-1")
> | (width . 80)
> | (height . 30))
> | #+end_src
> `
>
> It should be clear what this is about. On the office computer you would
> prepare the file headers to exclude the tags HOME and LAPTOP from being
> tangled and, after saving/tangling the file, you would have a nice init
> file suiting this computer. At home the same by excluding the other tags
> etc.
>
> This would save a lot of work and you would have a tidy way to maintain
> all your init files without (if (string-equal (system-name) clauses.
>
> If the noexport tag worked, it would also save a lot of time and mess
> when debugging your init file in case of an error.
>
> I don't actually understand why the developers decided not to implement
> export filtering in the tangling operations. I know about the COMMENT
> keyword, but the above example should make clear that this solution is
> far from handy.
>
> Maybe there is another way that escaped me so far?
>
> All best,
>
> Sven
>
>
>


Re: [O] Feature request: Maintaining multiple init files with one org file

2018-07-30 Thread Sven Bretfeld
Hi Eric

So all in all I feel that there is a demand for my suggestion. Orgmode
has the power to yield a real good solution for centralized init file
maintenance, but at the moment we have to help ourselves with
workarounds. Tag-filtering for tangling functions would be the best way
to go in the future. I'm not a programmer, otherwise I would try to
implement this. For now I can only hope that somebody competent would do
it.

For the time being, here is my workaround which I developed inspired by
Amin's approach. I describe everything for whoever else is looking for a
similar solution:

, ~/aktuell/emacs/emacs-config.org
|
| * Init File
| ** Hostname Identification
|This section defines variables for all use cases: Some code is needed
|only for one machine, some for a sub-group (e.g. all computers
|running Linux or all computers having large monitors etc.), some for all 
computers.
|
|#+begin_src emacs-lisp :tangle (if allhosts "~/.emacs")
|;; variable for my PC at home
|(defvar homepc nil) ;; variable for my PC at home
|(if (string-match (system-name) "hostname-home") ;<--- set your hostname 
here
|(setq homepc t))
|
|;; variable for my PC at office
|(defvar officepc nil)
|(if (string-match (system-name) "hostname-office") ;<--- set your hostname 
here
|(setq officepc t))
|
|;; variable for my laptop
|(defvar laptop nil)
|(if (string-match (system-name) "hostname-laptop") ;<--- set your hostname 
here
|(setq laptop t))
|
|;; variable for Termux/Android
|(defvar andr nil)
|(if (string-match (system-name) "localhost") ;<--- Termux uses "localhost"
|(setq andr t))
|
|;; variable for all desktop machines together (i.e. home+office in my case)
|(defvar pcs nil)
|(if (string-match (system-name) "hostname-home\|hostname-office") <--- set 
your hostnames here
|(setq pcs t))
|
|;; variable for all GNU/Linux machines together (home+office+laptop)
|(defvar allgnu nil)
|(if (string-match (system-name) 
"hostname-home\|hostname-office\|hostname-laptop") <--- set your hostnames here
|(setq allgnu t))
|
|;; variable for all machines together (home+office+laptop+Android)
|(defvar allhosts nil)
|(if (string-match (system-name) 
"hostname-home\|hostname-office\|hostname-laptop\|localhost")
|(setq allhosts t))
| #+end_src
| ** Startup File
| *** Linux
| The code in this section is needed for the init files on all
| computers running GNU/Linux (variable: allgnu)
|  #+begin_src emacs-lisp :tangle (if allgnu "~/.emacs")
|  (defun tangle-init ()
|"If the current buffer is 'emacs-config.org' the code-blocks are
|  tangled, and the tangled file is compiled."
|(when (equal (buffer-file-name)
|   (expand-file-name "~/aktuell/emacs/emacs-config.org"));<---put 
name of this file here
|  ;; Avoid running hooks when tangling.
|  (let ((prog-mode-hook nil))
|(org-babel-tangle
|
|  (add-hook 'after-save-hook 'tangle-init)
|  #+end_src
| *** Android
| The code in this section is needed only for emacs running on Android
| (variable: andr).
|  #+begin_src emacs-lisp :tangle (if andr "~/.emacs")
|  (defun tangle-init ()
|"If the current buffer is 'emacs-config.org' the code-blocks are
|  tangled, and the tangled file is compiled."
|(when (equal (buffer-file-name)
|   (expand-file-name
|  "/sdcard/Aktuell/emacs/emacs-config.org"));<---put name of this file with 
the Android path here
|  ;; Avoid running hooks when tangling.
|  (let ((prog-mode-hook nil))
|(org-babel-tangle
|
|  (add-hook 'after-save-hook 'tangle-init)
|  #+end_src
|
| * Other configurations whatsoever
|   ...
|
`

Every section of source-code starts with: `#+begin_src emacs-lisp
:tangle' and a lisp expression assigning the following source code
section to one of the defined variables (homepc, officepc, laptop, andr,
pcs, allgnu or allhosts). The code will then end up in the actual init
file (~/.emacs) only if the present machine belongs to the respective
group, i.e. if this variable is non-nil for it. If the variable is nil,
the code section will be ignored on the respective machine. All you have
to do is to sync this file to each machine, visit it on each and save it
again (which triggers the generation of the .emacs file).

Every piece of source code needs to have one of these expressions
(actually "allhosts" could do without, since it is the default case if
you have headline_args set as shown in my initial email). This is a bit
more clumsy than it would be if we could use org tags but it's easier
and clearer than including hundreds of if-conditions to the code itself.

Thank you for all your help,

Sven

Eric S Fraga writes:

> On Sunday, 29 Jul 2018 at 12:42, Sven Bretfeld wrote:
>
> [...]
>
>> At the moment I have a separate .emacs for the tablet and have to

Re: [O] Feature request: Maintaining multiple init files with one org file

2018-07-30 Thread Eric S Fraga
On Sunday, 29 Jul 2018 at 12:42, Sven Bretfeld wrote:

[...]

> At the moment I have a separate .emacs for the tablet and have to
> remember changing this file, for ex. whenever I include a new file in
> the org-agenda-files list. This could be much more tidy with an org
> approach.

The approach I take, trying to use the same init file for 4 quite
different systems (including termux on Android at one point), is to have
a very small .emacs for each which sets up system specific variables
(e.g. paths and default face) and then loads the common init file.  The
latter is managed/written in org but the .emacs (or equivalently
.emacs.d/init.el) files for each system are not as they are typically
just a few lines long.

> I'm trying to use customize as little as possible, since AFAIK there is
> no way to let customize use an org file instead of a "real" init file.

I also try to minimize the use of customize but I do use it.  For this,
I make sure that emacs doesn't use the init file for saving
customization information but uses a custom-file I specify.

-- 
Eric S Fraga via Emacs 27.0.50, Org release_9.1.13-753-g2ec5d3



Re: [O] Feature request: Maintaining multiple init files with one org file

2018-07-29 Thread Sven Bretfeld
Hi Armin

That's an interesting approach. I didn't think about giving arguments to
the :tangle operator. This is basically what I was looking for. Just a
bit more to write to each relevant source block. I will give it a try.

Sven


Amin Bandali writes:

> Hello,
>
> Indeed, a tag-based solution (e.g. with :office:, :home:, etc)
> would be great; but what I do right now looks something like
> this:
>
> ,
> | #+property: header-args :tangle ~/.emacs
> |
> | * Default Frame
> |
> | ** All computers
> | #+begin_src emacs-lisp
> | (defvar myvar "testing")
> | #+end_src
> |
> | ** Office Computer
> | #+begin_src emacs-lisp :tangle (when (string= (system-name) "officepc") 
> "~/.emacs")
> | (setq default-frame-alist '(
> |   (font . "-PfEd-DejaVu Sans 
> Mono-normal-normal-normal-*-26-*-*-*-m-0-iso10646-1")
> |   (width . 102)
> |   (height . 41))
> | #+end_src
> |
> | ** Laptop
> | #+begin_src emacs-lisp :tangle (when (string= (system-name) "mylaptop") 
> "~/.emacs")
> | (setq default-frame-alist '(
> |   (font . "-PfEd-DejaVu Sans 
> Mono-normal-normal-normal-*-12-*-*-*-m-0-iso10646-1")
> |   (width . 80)
> |   (height . 30))
> | #+end_src
> |
> | ** More stuff for all computers
> |
> | #+begin_src emacs-lisp
> | (message myvar)
> | #+end_src
> `
>
> In other words, I use `when' and `string=' (from subr.el) and
> `system-name' to check the hostname.  If it matches what I want,
> I return the "~/.emacs" filename, nil otherwise.  Alternatively,
> you could probably use `if' and return "no" when it doesn't
> match, but :tangle nil seems to work just fine so I went with
> `when'.
>
> Hope that helps.
>
> Best,
>
> -amin




Re: [O] Feature request: Maintaining multiple init files with one org file

2018-07-29 Thread Sven Bretfeld
Hi

Thanks for the answer.

Tim Cross writes:

> As your emacs init file is really just a lisp program, it is relatively
> easy to implement multiple environment support within the file itself,
> which is what I do. At the start of my init file, I just have some elisp
> which sets variables representing the platform (linux or mac), the
> hostname (I have both a linux and mac box at home and work) and the
> profile (home/work). Then it is just if/cond/when conditionals where
> needed. I use org to store the file mainly for documentation purposes
> and will have the same file on all platforms. The advantage is that it
> is the same file on all platforms, the disadvantage is that it is larger
> and probably more complex than it would be if you tangled different
> files per system.

This is pretty much how I do it at the moment. Complexity is indeed the
problem here. I have Emacs also running on an Android tablet under
Termux. This one needs quite a lot of adjustments to the init
file. Already the paths to the org files and to some non-elpa/melpa
packages are different. Other packages are not available on Termux
(e.g. aspell) or not meaningful at all (X-related stuff, mu4e
etc.). Having the same init file here as on the other computers, would
easily end up in a mess of IFs and WHENs (and probably slow down the
start process on Android).

At the moment I have a separate .emacs for the tablet and have to
remember changing this file, for ex. whenever I include a new file in
the org-agenda-files list. This could be much more tidy with an org
approach.

> For me this is just 6 of one and half a dozen of the other. YMMV. I do
> find there are some things best set/managed via Emacs' custom facility,
> so the most useful bit in my init file is the bit which loads different
> custom files based on the platform. I don't bother keeping the custom
> files in git, so they stay local to each system. I find using custom to
> manage face and font settings particularly convenient over managing them
> by hand in my init file.

I'm trying to use customize as little as possible, since AFAIK there is
no way to let customize use an org file instead of a "real" init file.

Sven



Re: [O] Feature request: Maintaining multiple init files with one org file

2018-07-28 Thread Tim Cross


I suspect part of the reason org doesn't have specific support for this
is because for many, solving the multiple machine/multiple
platform/multiple environment issue pre-dates org and so wasn't an itch
needing to be scratched. I've been using pretty much the same approach
since emacs 21.

As your emacs init file is really just a lisp program, it is relatively
easy to implement multiple environment support within the file itself,
which is what I do. At the start of my init file, I just have some elisp
which sets variables representing the platform (linux or mac), the
hostname (I have both a linux and mac box at home and work) and the
profile (home/work). Then it is just if/cond/when conditionals where
needed. I use org to store the file mainly for documentation purposes
and will have the same file on all platforms. The advantage is that it
is the same file on all platforms, the disadvantage is that it is larger
and probably more complex than it would be if you tangled different
files per system.

For me this is just 6 of one and half a dozen of the other. YMMV. I do
find there are some things best set/managed via Emacs' custom facility,
so the most useful bit in my init file is the bit which loads different
custom files based on the platform. I don't bother keeping the custom
files in git, so they stay local to each system. I find using custom to
manage face and font settings particularly convenient over managing them
by hand in my init file.

Tim

Sven Bretfeld  writes:

> Hi
>
> I don't know how you guys maintain init files for different hosts. I
> have one org-file with the header:
>
> #+PROPERTY: header-args :tangle ~/.emacs
>
> The file is synced to all my machines and produces the local init files
> on each. Most configurations are shared, but some are host-specific
> (e.g. font size).
>
> Sadly export filtering does not work with the tangle function. It would
> be nice to be able to do something like:
>
> ,
> | * Default Frame
> | ** Office Computer:OFFICE:
> | #+begin_src emacs-lisp
> | (setq default-frame-alist '(
> |   (font . "-PfEd-DejaVu Sans 
> Mono-normal-normal-normal-*-26-*-*-*-m-0-iso10646-1")
> |   (width . 102)
> |   (height . 41))
> | #+end_src
> |
> | ** Computer at home   :HOME:
> | #+begin_src emacs-lisp
> | (setq default-frame-alist '(
> |   (font . "-PfEd-DejaVu Sans 
> Mono-normal-normal-normal-*-18-*-*-*-m-0-iso10646-1")
> |   (width . 150)
> |   (height . 50))
> | #+end_src
> |
> | ** Laptop :LAPTOP:
> | #+begin_src emacs-lisp
> | (setq default-frame-alist '(
> |   (font . "-PfEd-DejaVu Sans 
> Mono-normal-normal-normal-*-12-*-*-*-m-0-iso10646-1")
> |   (width . 80)
> |   (height . 30))
> | #+end_src
> `
>
> It should be clear what this is about. On the office computer you would
> prepare the file headers to exclude the tags HOME and LAPTOP from being
> tangled and, after saving/tangling the file, you would have a nice init
> file suiting this computer. At home the same by excluding the other tags
> etc.
>
> This would save a lot of work and you would have a tidy way to maintain
> all your init files without (if (string-equal (system-name) clauses.
>
> If the noexport tag worked, it would also save a lot of time and mess
> when debugging your init file in case of an error.
>
> I don't actually understand why the developers decided not to implement
> export filtering in the tangling operations. I know about the COMMENT
> keyword, but the above example should make clear that this solution is
> far from handy.
>
> Maybe there is another way that escaped me so far?
>
> All best,
>
> Sven


--
Tim Cross



Re: [O] Feature request: Maintaining multiple init files with one org file

2018-07-28 Thread Amin Bandali
Hello,

Indeed, a tag-based solution (e.g. with :office:, :home:, etc)
would be great; but what I do right now looks something like
this:

,
| #+property: header-args :tangle ~/.emacs
|
| * Default Frame
|
| ** All computers
| #+begin_src emacs-lisp
| (defvar myvar "testing")
| #+end_src
|
| ** Office Computer
| #+begin_src emacs-lisp :tangle (when (string= (system-name) "officepc") 
"~/.emacs")
| (setq default-frame-alist '(
| (font . "-PfEd-DejaVu Sans 
Mono-normal-normal-normal-*-26-*-*-*-m-0-iso10646-1")
| (width . 102)
| (height . 41))
| #+end_src
|
| ** Laptop
| #+begin_src emacs-lisp :tangle (when (string= (system-name) "mylaptop") 
"~/.emacs")
| (setq default-frame-alist '(
| (font . "-PfEd-DejaVu Sans 
Mono-normal-normal-normal-*-12-*-*-*-m-0-iso10646-1")
| (width . 80)
| (height . 30))
| #+end_src
|
| ** More stuff for all computers
|
| #+begin_src emacs-lisp
| (message myvar)
| #+end_src
`

In other words, I use `when' and `string=' (from subr.el) and
`system-name' to check the hostname.  If it matches what I want,
I return the "~/.emacs" filename, nil otherwise.  Alternatively,
you could probably use `if' and return "no" when it doesn't
match, but :tangle nil seems to work just fine so I went with
`when'.

Hope that helps.

Best,

-amin



[O] Feature request: Maintaining multiple init files with one org file

2018-07-28 Thread Sven Bretfeld
Hi

I don't know how you guys maintain init files for different hosts. I
have one org-file with the header:

#+PROPERTY: header-args :tangle ~/.emacs

The file is synced to all my machines and produces the local init files
on each. Most configurations are shared, but some are host-specific
(e.g. font size).

Sadly export filtering does not work with the tangle function. It would
be nice to be able to do something like:

,
| * Default Frame
| ** Office Computer:OFFICE:
| #+begin_src emacs-lisp
| (setq default-frame-alist '(
| (font . "-PfEd-DejaVu Sans 
Mono-normal-normal-normal-*-26-*-*-*-m-0-iso10646-1")
| (width . 102)
| (height . 41))
| #+end_src
|
| ** Computer at home   :HOME:
| #+begin_src emacs-lisp
| (setq default-frame-alist '(
| (font . "-PfEd-DejaVu Sans 
Mono-normal-normal-normal-*-18-*-*-*-m-0-iso10646-1")
| (width . 150)
| (height . 50))
| #+end_src
|
| ** Laptop :LAPTOP:
| #+begin_src emacs-lisp
| (setq default-frame-alist '(
| (font . "-PfEd-DejaVu Sans 
Mono-normal-normal-normal-*-12-*-*-*-m-0-iso10646-1")
| (width . 80)
| (height . 30))
| #+end_src
`

It should be clear what this is about. On the office computer you would
prepare the file headers to exclude the tags HOME and LAPTOP from being
tangled and, after saving/tangling the file, you would have a nice init
file suiting this computer. At home the same by excluding the other tags
etc.

This would save a lot of work and you would have a tidy way to maintain
all your init files without (if (string-equal (system-name) clauses.

If the noexport tag worked, it would also save a lot of time and mess
when debugging your init file in case of an error.

I don't actually understand why the developers decided not to implement
export filtering in the tangling operations. I know about the COMMENT
keyword, but the above example should make clear that this solution is
far from handy.

Maybe there is another way that escaped me so far?

All best,

Sven