Adding a new blog post, emacs and org-mode
This commit is contained in:
parent
cce7789d0f
commit
2094c32421
1 changed files with 241 additions and 0 deletions
241
posts/text-editors/emacs-and-org-mode.rst
Normal file
241
posts/text-editors/emacs-and-org-mode.rst
Normal file
|
@ -0,0 +1,241 @@
|
||||||
|
.. title: Emacs and Org-mode
|
||||||
|
.. date: 2020-08-22
|
||||||
|
.. slug: emacs-and-org-mode
|
||||||
|
.. updated: 2020-08-22
|
||||||
|
.. status: published
|
||||||
|
.. tags: emacs, org-mode, configuration,
|
||||||
|
.. category: text-editors
|
||||||
|
.. authors: Elia el Lazkani
|
||||||
|
.. description: I ditched VSCode and moved back to Emacs... You heard me !
|
||||||
|
.. type: text
|
||||||
|
|
||||||
|
I have recently found out, late I know, that the *VSCode* distribution of the so called *Code - OSS* is exactly that; a distribution.
|
||||||
|
|
||||||
|
Let me make it clear, the *VSCode* binaries you download from **Microsoft** has an upstream the **GitHub repository*** named `VSCode <https://github.com/Microsoft/vscode>`_ but in fact is not exactly the same code.
|
||||||
|
**Microsoft** has already added a few gifts for you, including *telemetry*, not cool huh ?!
|
||||||
|
Well, they tell you this in the documentation, urrrmmm `somewhere <https://github.com/microsoft/vscode/wiki/Differences-between-the-repository-and-Visual-Studio-Code>`_.
|
||||||
|
|
||||||
|
At the same time, I was giving *Jupyter Notebook* a try. I worked on my previous post in it before writing down the final result as a blog post.
|
||||||
|
But at the back of my mind, there was always `Org-mode <https://orgmode.org/>`_.
|
||||||
|
|
||||||
|
Putting one and one together, you've guessed it. I have moved to *Emacs*... again... for the umm I can't remember time.
|
||||||
|
But this time, it is different ! I hope...
|
||||||
|
|
||||||
|
.. TEASER_END
|
||||||
|
|
||||||
|
Back story
|
||||||
|
==========
|
||||||
|
|
||||||
|
I was using *Jupyter Notebooks* as a way to write down notes. Organize things.
|
||||||
|
I had a work around the *output* and was able to clean it.
|
||||||
|
But let's face it, it might work but it is designed more towards other goals.
|
||||||
|
I want to write notes and the best way to work with notes is to keep in the text, literally.
|
||||||
|
I found a *VSCode* extension that can handle *Org-mode* in some capacity (I haven't tested it) so I decided to switch to *Emacs* and keep the extention as a backup.
|
||||||
|
|
||||||
|
Emacs Distribution of Doom
|
||||||
|
==========================
|
||||||
|
|
||||||
|
Haha ! Very funny, I know. I went with `Doom <https://github.com/hlissner/emacs-doom-themes>`_.
|
||||||
|
Why? You may ask. I don't really have a good answer for you except the following.
|
||||||
|
|
||||||
|
* I didn't want to start from scratch, I wanted something with batteries included.
|
||||||
|
* At the same time, I've tried *Doom* before and I like how it does things.
|
||||||
|
It is logical to me while at the same time very configurable.
|
||||||
|
* I was able to get up and running very quickly. Granted, my needs are few.
|
||||||
|
* I got *Python* and *Golang* auto-completion and *evil* mode. I'm good to go !
|
||||||
|
|
||||||
|
Now let's dig down to my main focus here. Sure I switched editors but it was for a reason; **Org-mode**.
|
||||||
|
|
||||||
|
Org-mode Configuration
|
||||||
|
======================
|
||||||
|
|
||||||
|
I will be talking about two different configuartion options here.
|
||||||
|
I am new to emacs so I will try to explain everything.
|
||||||
|
|
||||||
|
The two options are related to the difference between a *vanilla* configuration and *Doom*'s version of the configuration.
|
||||||
|
The differences are minor but they are worth talking about.
|
||||||
|
|
||||||
|
New Org File
|
||||||
|
------------
|
||||||
|
|
||||||
|
If you've used *Org-mode* before and created *org files*, you already know that you need to set a few values at the top of the file. These include the *title*, *author*, *description* and a different other values to change setting and/or behavior.
|
||||||
|
|
||||||
|
It is a bit of a manual labor to write these few lines at the beginning of every file. I wanted to automate that. So I got inspiration from `shakthimaan <https://gitlab.com/shakthimaan/operation-blue-moon>`_.
|
||||||
|
|
||||||
|
I used his method to create a small ``define-skeleton`` for a header.
|
||||||
|
It looks something like this.
|
||||||
|
|
||||||
|
.. code:: lisp
|
||||||
|
|
||||||
|
(define-skeleton generate-new-header-org
|
||||||
|
"Prompt for title, description and tags"
|
||||||
|
nil
|
||||||
|
'(setq title (skeleton-read "Title: "))
|
||||||
|
'(setq author (skeleton-read "Author: "))
|
||||||
|
'(setq description (skeleton-read "Description: "))
|
||||||
|
'(setq tags (skeleton-read "tags: "))
|
||||||
|
"#+TITLE: " title \n
|
||||||
|
"#+AUTHOR: " author \n
|
||||||
|
"#+DESCRIPTION: " description \n
|
||||||
|
"#+TAGS: " tags \n
|
||||||
|
)
|
||||||
|
|
||||||
|
You can use this later with ``M-x`` + ``genrate-new-header-org``.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
``M-x`` is the **Meta** key and **x** combination.
|
||||||
|
Your **Meta** key can differ between the **Alt** on *Linux* and **Command** on *Mac OS X*.
|
||||||
|
|
||||||
|
``M-x`` will open a prompt for you to write in. Write the name you gave the skeleton, in this case it is ``generate-new-header-org`` and then hit the *Return*.
|
||||||
|
|
||||||
|
New Task
|
||||||
|
--------
|
||||||
|
|
||||||
|
`shakthimaan <https://gitlab.com/shakthimaan/operation-blue-moon>`_ already created something for this. It looks like the following.
|
||||||
|
|
||||||
|
.. code:: lisp
|
||||||
|
|
||||||
|
;; Create a new skeleton to generate a new =Task=
|
||||||
|
(define-skeleton insert-org-entry
|
||||||
|
"Prompt for task, estimate and category"
|
||||||
|
nil
|
||||||
|
'(setq task (skeleton-read "Task: "))
|
||||||
|
'(setq estimate (skeleton-read "Estimate: "))
|
||||||
|
'(setq owner (skeleton-read "Owner: "))
|
||||||
|
'(setq category (skeleton-read "Category: "))
|
||||||
|
'(setq timestamp (format-time-string "%s"))
|
||||||
|
"** " task \n
|
||||||
|
":PROPERTIES:" \n
|
||||||
|
":ESTIMATED: " estimate \n
|
||||||
|
":ACTUAL:" \n
|
||||||
|
":OWNER: " owner \n
|
||||||
|
":ID: " category "." timestamp \n
|
||||||
|
":TASKID: " category "." timestamp \n
|
||||||
|
":END:")
|
||||||
|
|
||||||
|
This can also be used like the one above with ``M-x`` + ``insert-org-entry``.
|
||||||
|
|
||||||
|
Doom specific configuration
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
Whatever defined so far should work if you just add it to your configuration but if you use *Doom* it would a nice touch to integrate it with the workflow.
|
||||||
|
|
||||||
|
In ``~/.doom.d/config.el``, wrap the previous definitions with ``(after! org)``.
|
||||||
|
It's a nice touch to add these skeletons after *Org-mode* has loaded.
|
||||||
|
|
||||||
|
.. code:: lisp
|
||||||
|
|
||||||
|
(after! org
|
||||||
|
;; Create a skeleton to generate header org
|
||||||
|
(define-skeleton generate-new-header-org
|
||||||
|
"Prompt for title, description and tags"
|
||||||
|
nil
|
||||||
|
'(setq title (skeleton-read "Title: "))
|
||||||
|
'(setq author (skeleton-read "Author: "))
|
||||||
|
'(setq description (skeleton-read "Description: "))
|
||||||
|
'(setq tags (skeleton-read "tags: "))
|
||||||
|
"#+TITLE: " title \n
|
||||||
|
"#+AUTHOR: " author \n
|
||||||
|
"#+DESCRIPTION: " description \n
|
||||||
|
"#+TAGS: " tags \n)
|
||||||
|
|
||||||
|
;; Create a new skeleton to generate a new =Task=
|
||||||
|
(define-skeleton insert-org-entry
|
||||||
|
"Prompt for task, estimate and category"
|
||||||
|
nil
|
||||||
|
'(setq task (skeleton-read "Task: "))
|
||||||
|
'(setq estimate (skeleton-read "Estimate: "))
|
||||||
|
'(setq owner (skeleton-read "Owner: "))
|
||||||
|
'(setq category (skeleton-read "Category: "))
|
||||||
|
'(setq timestamp (format-time-string "%s"))
|
||||||
|
"** " task \n
|
||||||
|
":PROPERTIES:" \n
|
||||||
|
":ESTIMATED: " estimate \n
|
||||||
|
":ACTUAL:" \n
|
||||||
|
":OWNER: " owner \n
|
||||||
|
":ID: " category "." timestamp \n
|
||||||
|
":TASKID: " category "." timestamp \n
|
||||||
|
":END:")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
If you modify any file in ``~/.doom.d/``, do not forget to run ``doom sync`` and ``doom doctor`` to update and check your configuration respectively.
|
||||||
|
|
||||||
|
Final touches
|
||||||
|
-------------
|
||||||
|
|
||||||
|
I wanted to add it to the menu system that comes with *Doom* so I included the following in my ``(after! ...)`` block.
|
||||||
|
|
||||||
|
.. code:: lisp
|
||||||
|
|
||||||
|
;; Add keybindings with the leader menu for everything above
|
||||||
|
(map! :map org-mode-map
|
||||||
|
(:leader
|
||||||
|
(:prefix ("m", "+<localleader>")
|
||||||
|
:n :desc "Generate New Header Org" "G" 'generate-new-header-org
|
||||||
|
:n :desc "New Task Entry" "N" 'insert-org-entry
|
||||||
|
))
|
||||||
|
)
|
||||||
|
|
||||||
|
Making the final configuration look like the following.
|
||||||
|
|
||||||
|
.. code:: lisp
|
||||||
|
|
||||||
|
(after! org
|
||||||
|
;; Create a skeleton to generate header org
|
||||||
|
(define-skeleton generate-new-header-org
|
||||||
|
"Prompt for title, description and tags"
|
||||||
|
nil
|
||||||
|
'(setq title (skeleton-read "Title: "))
|
||||||
|
'(setq author (skeleton-read "Author: "))
|
||||||
|
'(setq description (skeleton-read "Description: "))
|
||||||
|
'(setq tags (skeleton-read "tags: "))
|
||||||
|
"#+TITLE: " title \n
|
||||||
|
"#+AUTHOR: " author \n
|
||||||
|
"#+DESCRIPTION: " description \n
|
||||||
|
"#+TAGS: " tags \n)
|
||||||
|
|
||||||
|
;; Create a new skeleton to generate a new =Task=
|
||||||
|
(define-skeleton insert-org-entry
|
||||||
|
"Prompt for task, estimate and category"
|
||||||
|
nil
|
||||||
|
'(setq task (skeleton-read "Task: "))
|
||||||
|
'(setq estimate (skeleton-read "Estimate: "))
|
||||||
|
'(setq owner (skeleton-read "Owner: "))
|
||||||
|
'(setq category (skeleton-read "Category: "))
|
||||||
|
'(setq timestamp (format-time-string "%s"))
|
||||||
|
"** " task \n
|
||||||
|
":PROPERTIES:" \n
|
||||||
|
":ESTIMATED: " estimate \n
|
||||||
|
":ACTUAL:" \n
|
||||||
|
":OWNER: " owner \n
|
||||||
|
":ID: " category "." timestamp \n
|
||||||
|
":TASKID: " category "." timestamp \n
|
||||||
|
":END:")
|
||||||
|
|
||||||
|
(map! :map org-mode-map
|
||||||
|
(:leader
|
||||||
|
(:prefix ("m", "+<localleader>")
|
||||||
|
:n :desc "Generate New Header Org" "G" 'generate-new-header-org
|
||||||
|
:n :desc "New Task Entry" "N" 'insert-org-entry
|
||||||
|
)))
|
||||||
|
)
|
||||||
|
|
||||||
|
What do I do now ?
|
||||||
|
==================
|
||||||
|
|
||||||
|
You might be asking yourself at this point, what does this all mean ?
|
||||||
|
What do I do with this ? Where do I go ?
|
||||||
|
|
||||||
|
Well here's the thing. You find yourself wanting to create a new *org file*.
|
||||||
|
You do so in emacs and follow it with ``M-x`` + ``generate-new-header-org`` (or ``SPC m G`` in **Doom**). *Emacs* will ask you a few questions in the bottom left corner and once you answer then, your header should be all set.
|
||||||
|
|
||||||
|
You can follow that with ``M-x`` + ``insert-org-entry`` (or ``SPC m N``) to generate a task. This will also ask you for input in the bottom left corner.
|
||||||
|
|
||||||
|
Conclusion
|
||||||
|
==========
|
||||||
|
|
||||||
|
This should help me pick up the usage of *Org-mode* faster. It is also a good idea if you've already configured your *Emacs* to read all your *org file* for a wider **agenda** view.
|
Reference in a new issue