Getting work-specific code to work
This includes some org-specific stuff, like my Sprint and clipboard code.
This commit is contained in:
parent
d7b3bd3ef7
commit
d3f14de2ee
6 changed files with 767 additions and 27 deletions
7
.gitignore
vendored
7
.gitignore
vendored
|
@ -1,6 +1,3 @@
|
|||
*~
|
||||
/bootstrap.el
|
||||
/ha-config.el
|
||||
/ha-display.el
|
||||
/ha-org-word-processor.el
|
||||
/ha-org.el
|
||||
/*.el
|
||||
/ha-work.org
|
||||
|
|
|
@ -57,6 +57,10 @@ The following packages come with Emacs, but seems like they still need loading:
|
|||
#+BEGIN_SRC emacs-lisp
|
||||
(require 'subr-x)
|
||||
#+END_SRC
|
||||
Ugh. Why am I getting this error?
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun first (elt) (car elt))
|
||||
#+END_SRC
|
||||
While most libraries will take care of their dependencies, I want to install /my dependent libraries/. Especially, [[https://github.com/magnars/.emacs.d/][Magnar Sveen]]'s Clojure-inspired [[https://github.com/magnars/dash.el][dash.el]] project:
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(use-package dash)
|
||||
|
@ -78,31 +82,54 @@ Much of my more complicated code comes from my website essays and other projects
|
|||
#+END_SRC
|
||||
|
||||
Hopefully, this will tie me over while I transition.
|
||||
** Emacs Server Control
|
||||
Sure the Emacs application will almost always have the =server-start= going, however, I need to control it just a bit (because I often have two instances running on some of my machines). What /defines/ the Emacs instance for work changes ... often:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun ha-emacs-for-work? ()
|
||||
"Return non-nil when the Emacs application's location matches as one for work.
|
||||
Currently, this is the `emacs-plus' app that I have built with
|
||||
the native-comp model, but I reserve the right to change this."
|
||||
(->> Info-default-directory-list
|
||||
(first)
|
||||
(s-split "/")
|
||||
(--filter (s-starts-with? "emacs-plus" it))
|
||||
(first)))
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(if (ha-emacs-for-work?)
|
||||
(setq server-name "work")
|
||||
(setq server-name "personal"))
|
||||
|
||||
(server-start)
|
||||
#+END_SRC
|
||||
* Load the Rest
|
||||
The following loads the rest of my org-mode literate files. I add them as they are /ready/, but eventually, I'll trim this up into a nicer pattern.
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(dolist (file '("ha-config.org"
|
||||
"ha-display.org"
|
||||
"ha-org.org"
|
||||
"ha-org-word-processor.org"
|
||||
;; "org-clipboard.org"
|
||||
;; "org-journaling.org"
|
||||
;; "org-publishing.org"
|
||||
;; "org-sprint.org"
|
||||
;; "capturing-notes.org"
|
||||
;; "general-programming.org"
|
||||
;; "ha-agendas.org"
|
||||
;; "ha-email.org"
|
||||
;; "ha-irc.org"
|
||||
;; "ha-passwords.org"
|
||||
;; "ha-remoting.org"
|
||||
;; "my-feeds.org"
|
||||
))
|
||||
(org-babel-load-file (f-join hamacs-source-dir file)))
|
||||
(dolist (file `("ha-config.org"
|
||||
"ha-display.org"
|
||||
"ha-org.org"
|
||||
"ha-org-word-processor.org"
|
||||
"ha-org-clipboard.org"
|
||||
;; "org-journaling.org"
|
||||
;; "org-publishing.org"
|
||||
"ha-org-sprint.org"
|
||||
;; "capturing-notes.org"
|
||||
;; "general-programming.org"
|
||||
;; "ha-agendas.org"
|
||||
;; "ha-email.org"
|
||||
;; "ha-irc.org"
|
||||
;; "ha-passwords.org"
|
||||
;; "ha-remoting.org"
|
||||
;; "my-feeds.org"
|
||||
,(when (ha-emacs-for-work?)
|
||||
"ha-work.org")))
|
||||
(org-babel-load-file (f-join hamacs-source-dir file)))
|
||||
#+END_SRC
|
||||
We can test/debug any individual file, via:
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(org-babel-load-file (f-join hamacs-source-dir "ha-config.org"))
|
||||
#+BEGIN_SRC emacs-lisp :tangle no
|
||||
(org-babel-load-file (f-join hamacs-source-dir "ha-org-word-processor.org"))
|
||||
#+END_SRC
|
||||
* Technical Artifacts :noexport:
|
||||
Let's provide a name so that the file can be required:
|
||||
|
|
78
ha-org-babel.org
Normal file
78
ha-org-babel.org
Normal file
|
@ -0,0 +1,78 @@
|
|||
#+TITLE: Literate Programming with Org
|
||||
#+AUTHOR: Howard X. Abrams
|
||||
#+EMAIL: howard.abrams@gmail.com
|
||||
#+DATE: 2021-11-05
|
||||
#+FILETAGS: :emacs:
|
||||
|
||||
This section is primarily about development in a literate way, especially focused on [[http://howardism.org/Technical/Emacs/literate-devops.html][literate devops]].
|
||||
|
||||
#+BEGIN_SRC emacs-lisp :exports none
|
||||
;;; ha-org-babel.el --- -*- lexical-binding: t; -*-
|
||||
;;
|
||||
;; Copyright (C) 2021 Howard X. Abrams
|
||||
;;
|
||||
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
||||
;; Maintainer: Howard X. Abrams <howard.abrams@gmail.com>
|
||||
;; Created: November 5, 2021
|
||||
;;
|
||||
;; This file is not part of GNU Emacs.
|
||||
;;
|
||||
;; *NB:* Do not edit this file. Instead, edit the original literate file at:
|
||||
;; /Users/howard.abrams/other/hamacs/ha-org-babel.org
|
||||
;; And tangle the file to recreate this one.
|
||||
;;
|
||||
;;; Code:
|
||||
#+END_SRC
|
||||
|
||||
* Introduction
|
||||
Let's turn on all the languages:
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(use-package org
|
||||
:init
|
||||
(setq org-confirm-babel-evaluate nil
|
||||
org-src-fontify-natively t
|
||||
org-src-tab-acts-natively t)
|
||||
:config
|
||||
(add-to-list 'org-src-lang-modes '("dot" . "graphviz-dot"))
|
||||
|
||||
(org-babel-do-load-languages 'org-babel-load-languages
|
||||
'((shell . t)
|
||||
(js . t)
|
||||
(emacs-lisp . t)
|
||||
(clojure . t)
|
||||
(python . t)
|
||||
(ruby . t)
|
||||
(dot . t)
|
||||
(css . t)
|
||||
(plantuml . t))))
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: t
|
||||
|
||||
|
||||
|
||||
* Technical Artifacts :noexport:
|
||||
|
||||
Let's provide a name so that the file can be required:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp :exports none
|
||||
(provide 'ha-org-babel)
|
||||
;;; ha-org-babel.el ends here
|
||||
#+END_SRC
|
||||
|
||||
Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: ~C-c C-c~
|
||||
|
||||
#+DESCRIPTION:
|
||||
|
||||
#+PROPERTY: header-args:sh :tangle no
|
||||
#+PROPERTY: header-args:emacs-lisp :tangle yes
|
||||
#+PROPERTY: header-args :results none :eval no-export :comments no mkdirp yes
|
||||
|
||||
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil date:nil
|
||||
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
|
||||
#+INFOJS_OPT: view:nil toc:nil ltoc:t mouse:underline buttons:0 path:http://orgmode.org/org-info.js
|
||||
|
||||
# Local Variables:
|
||||
# eval: (add-hook 'after-save-hook #'org-babel-tangle t t)
|
||||
# End:
|
190
ha-org-clipboard.org
Normal file
190
ha-org-clipboard.org
Normal file
|
@ -0,0 +1,190 @@
|
|||
#+TITLE: Pasting the Org Clipboard
|
||||
#+AUTHOR: Howard X. Abrams
|
||||
#+EMAIL: howard.abrams@gmail.com
|
||||
#+DATE: 2020-09-15
|
||||
#+FILETAGS: :emacs:
|
||||
|
||||
A literate programming file of functions for formatting the clipboard.
|
||||
# *Note:* After each change, /tangle it/ to the source destination with ~C-c C-v t~.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp :exports none
|
||||
;;; org-clipboard.el --- A literate programming file of functions for formatting the clipboard. -*- lexical-binding: t; -*-
|
||||
;;
|
||||
;; Copyright (C) 2020 Howard X. Abrams
|
||||
;;
|
||||
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
||||
;; Maintainer: Howard X. Abrams <howard.abrams@gmail.com>
|
||||
;; Created: September 15, 2020
|
||||
;;
|
||||
;; This file is not part of GNU Emacs.
|
||||
;;
|
||||
;; *NB:* Do not edit this file. Instead, edit the original literate file at:
|
||||
;; /home/howard/other/hamacs/org-clipboard.org
|
||||
;; And tangle the file to recreate this one.
|
||||
;;
|
||||
;;; Code:
|
||||
#+END_SRC
|
||||
* Introduction
|
||||
I would like to paste the formatted contents of the clipboard into an Org file /as org-formatted text/.
|
||||
* The Clipboard
|
||||
|
||||
Functions to help convert content from the operating system's clipboard into org-mode-compatible text.
|
||||
|
||||
Each operating system as a different way of working with the clipboard, so let's create an operating-system abstraction:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun ha/get-clipboard ()
|
||||
"Returns a list where the first entry is the content type,
|
||||
either :html or :text, and the second is the clipboard contents."
|
||||
(if (eq system-type 'darwin)
|
||||
(ha/get-mac-clipboard)
|
||||
(ha/get-linux-clipboard)))
|
||||
#+END_SRC
|
||||
|
||||
Let's define the clipboard for a Mac. The challenge here is that we need to binary unpack the data from a call to Applescript.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun ha/get-mac-clipboard ()
|
||||
"Returns a list where the first entry is the content type,
|
||||
either :html or :text, and the second is the clipboard contents."
|
||||
(destructuring-bind (exit-code contents)
|
||||
(shell-command-with-exit-code "osascript" "-e" "the clipboard as \"HTML\"")
|
||||
(if (= 0 exit-code)
|
||||
(list :html (ha/convert-applescript-to-html contents))
|
||||
(list :text (shell-command-to-string "osascript -e 'the clipboard'")))))
|
||||
|
||||
(defun ha/convert-applescript-to-html (packed-contents)
|
||||
"Applescript's clipboard returns the contents in a packed array.
|
||||
Convert and return this encoding into a UTF-8 string."
|
||||
(cl-flet ((hex-pack-bytes (tuple) (string-to-number (apply 'string tuple) 16)))
|
||||
(let* ((data (-> packed-contents
|
||||
(substring 10 -2) ; strips off the =«data RTF= and =»\= bits
|
||||
(string-to-list)))
|
||||
(byte-seq (->> data
|
||||
(-partition 2) ; group each two hex characters into tuple
|
||||
(mapcar #'hex-pack-bytes))))
|
||||
(decode-coding-string
|
||||
(mapconcat #'byte-to-string byte-seq "") 'utf-8))))
|
||||
#+END_SRC
|
||||
|
||||
And define the same interface for Linux. Keep in mind, we need the exit code from calling a process, so I am going to define/use a helper function (that really should go into the piper project).
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun ha/get-linux-clipboard ()
|
||||
"Return the clipbaard for a Unix-based system. See `ha/get-clipboard'."
|
||||
(destructuring-bind (exit-code contents)
|
||||
(shell-command-with-exit-code "xclip" "-o" "-t" "text/html")
|
||||
(if (= 0 exit-code)
|
||||
(list :html contents)
|
||||
(list :text (shell-command-to-string "xclip -o")))))
|
||||
|
||||
(defun shell-command-with-exit-code (program &rest args)
|
||||
"Run PROGRAM with ARGS and return the exit code and output in a list."
|
||||
(with-temp-buffer
|
||||
(list (apply 'call-process program nil (current-buffer) nil args)
|
||||
(buffer-string))))
|
||||
#+END_SRC
|
||||
|
||||
* Converting from Slack
|
||||
|
||||
We can assume that most non-HTML text could be Slack-like:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun ha/slack-to-markdown-buffer ()
|
||||
"Odd function that converts Slack’s version of Markdown (where
|
||||
code is delimited with triple backticks) into a more formal
|
||||
four-space indent markdown style."
|
||||
(goto-char (point-min))
|
||||
;; Begin by converting all Carriage Returns to line feeds:
|
||||
(while (re-search-forward "
" nil t)
|
||||
(replace-match "
|
||||
"))
|
||||
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward "```" nil t)
|
||||
(replace-match "
|
||||
|
||||
")
|
||||
(let ((starting-bounds (point)))
|
||||
(if (re-search-forward "```[ \t]*" nil t)
|
||||
(let ((ending-bounds (point)))
|
||||
(replace-match "
|
||||
|
||||
")
|
||||
(goto-char starting-bounds)
|
||||
(while (< (point) ending-bounds)
|
||||
(next-line)
|
||||
(beginning-of-line)
|
||||
(insert " ")))))))
|
||||
#+END_SRC
|
||||
|
||||
* Converting to Org
|
||||
|
||||
Let's work top-down at this point with the interactive function that inserts the clipboard into the current buffer:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun ha/org-yank-clipboard ()
|
||||
"Yanks (pastes) the contents of the Apple Mac clipboard in an
|
||||
org-mode-compatible format."
|
||||
(interactive)
|
||||
(insert (ha/org-clipboard)))
|
||||
#+END_SRC
|
||||
|
||||
The heavy lifting, however is done by this function. Note that I will need another function to tidy up the output from =pandoc= that will be more to my liking.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun ha/org-clipboard ()
|
||||
"Return the contents of the clipboard in org-mode format."
|
||||
(seq-let (type contents) (ha/get-clipboard)
|
||||
(with-temp-buffer
|
||||
(insert contents)
|
||||
(if (eq :html type)
|
||||
(shell-command-on-region (point-min) (point-max) "pandoc -f html -t org" t t)
|
||||
(ha/slack-to-markdown-buffer)
|
||||
(shell-command-on-region (point-min) (point-max) "pandoc -f markdown -t org" t t))
|
||||
(ha/html-paste-touchup)
|
||||
(buffer-substring-no-properties (point-min) (point-max)))))
|
||||
|
||||
(defun ha/html-paste-touchup ()
|
||||
"Attempts to fix the org produced by `pandoc'' that seems to plague us."
|
||||
(interactive)
|
||||
(dolist (combo '((" (edited) " " ") ; Slack appends this phrase that is never needed
|
||||
(" " " ") ; Pandoc's fixed space needs to go
|
||||
("\\\\\\\\$" "") ; Pandoc's fixed space needs to go
|
||||
("\\[\\[https://slack-imgs\\.com/.*\\.png\\]\\]" "") ;; Emoticons associated with a user
|
||||
("\\[\\[https://.*\\.slack\\.com/archives.*\\]\\[\\(.*\n.*\\)\\]\\]" "")
|
||||
("\\[\\[https://app\.slack\.com/team.*\\]\\[\\(.*\\)\n\\(.*\\)\\]\\]" " - *\\1 \\2:* ")
|
||||
("\\[\\[https://app\.slack\.com/team.*\\]\\[\\(.*\n.*\\)\\]\\]" " - *\\1:* ")
|
||||
("^- \\(.*\\)\\n " "- \\1 ")
|
||||
("^ *<<[0-9\.]+>>\n\n" ""))) ;; Slack includes these time things?
|
||||
(seq-let (search replace) combo
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward search nil t)
|
||||
(replace-match replace)))))
|
||||
#+END_SRC
|
||||
|
||||
* Keybinding to Paste into Org Files
|
||||
We
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(general-evil-define-key 'normal org-mode-map
|
||||
:prefix "SPC m"
|
||||
"y" 'ha/org-yank-clipboard)
|
||||
#+END_SRC
|
||||
|
||||
* Technical Artifacts :noexport:
|
||||
Let's provide a name so we can =require= this file:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(provide 'ha-org-clipboard)
|
||||
;;; ha-org-clipboard.el ends here
|
||||
#+END_SRC
|
||||
|
||||
#+DESCRIPTION: A literate programming version of functions for formatting the clipboard.
|
||||
|
||||
#+PROPERTY: header-args:sh :tangle no
|
||||
#+PROPERTY: header-args:emacs-lisp :tangle yes
|
||||
#+PROPERTY: header-args :results none :eval no-export :comments no mkdirp yes
|
||||
|
||||
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil date:nil
|
||||
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
|
||||
#+INFOJS_OPT: view:nil toc:nil ltoc:t mouse:underline buttons:0 path:http://orgmode.org/org-info.js
|
434
ha-org-sprint.org
Normal file
434
ha-org-sprint.org
Normal file
|
@ -0,0 +1,434 @@
|
|||
#+TITLE: My Sprint Calculations and Support
|
||||
#+AUTHOR: Howard X. Abrams
|
||||
#+EMAIL: howard.abrams@gmail.com
|
||||
#+DATE: 2020-09-25
|
||||
#+FILETAGS: :emacs:
|
||||
|
||||
A literate program for configuring org files for work-related notes.
|
||||
# *Note:* After each change, /tangle it/ to the source destination with ~C-c C-v t~.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp :exports none
|
||||
;;; org-sp rint.el --- A literate program for configuring org files for work-related notes. -*- lexical-binding: t; -*-
|
||||
;;
|
||||
;; Copyright (C) 2020 Howard X. Abrams
|
||||
;;
|
||||
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
||||
;; Maintainer: Howard X. Abrams <howard.abrams@gmail.com>
|
||||
;; Created: September 25, 2020
|
||||
;;
|
||||
;; This file is not part of GNU Emacs.
|
||||
;;
|
||||
;; *NB:* Do not edit this file. Instead, edit the original literate file at:
|
||||
;; /Users/howard.abrams/other/hamacs/org-sprint.org
|
||||
;; And tangle the file to recreate this one.
|
||||
;;
|
||||
;;; Code:
|
||||
#+END_SRC
|
||||
|
||||
* Introduction
|
||||
|
||||
At the beginning of each Sprint, I create a new org file dedicated to it. This workflow/technique strikes a balance between a single ever-growing file, and a thousand tiny ones. This also gives me a sense of continuity, as the filename of each sprint is date-based.
|
||||
|
||||
I want a single keybinding that always displays the current Sprint note file, regardless of what Sprint it is. This means, I need to have functions that can calculate what this is.
|
||||
|
||||
In order to have the Org Capture features to be able to write to correct locations in the current file, I need each file to follow a particular format. I create a [[file:snippets/org-mode/__sprint.org][sprint note template]] that will be automatically expanded with a new sprint.
|
||||
|
||||
This template needs the following functions:
|
||||
|
||||
- =sprint-current-name= to be both the numeric label as well as the nickname
|
||||
- =sprint-date-range= to include a org-formatted date range beginning and ending the sprint
|
||||
- =sprint-date-from-start= return a date for pre-scheduled and recurring meetings
|
||||
|
||||
* Naming Sprints
|
||||
|
||||
I give each sprint a nickname, based on a /theme/ of some sorts, alphabetized. Since our sprints are every two weeks, this allows me to go through the alphabet once. Yeah, my group likes to boringly /number/ the sprints, so I do both...mostly for myself.
|
||||
|
||||
At the beginning of the year, I choose a theme, and make a list for the upcoming sprints. In the org file, this is just a list, that gets /tangled/ into an actual Emacs LIsp list. This is pretty cool.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp :noweb yes
|
||||
(defvar sprint-nicknames
|
||||
(--map (replace-regexp-in-string " *[:#].*" "" (first it))
|
||||
'<<sprint-names-2021()>>)
|
||||
"List of 26 Sprint Nicknames from A to Z.")
|
||||
#+END_SRC
|
||||
** 2022
|
||||
|
||||
Fun sprint names for 2021 lists my favorite D&D monsters, also see [[https://list.fandom.com/wiki/List_of_monsters][this list of monsters]] from mythology and other sources:
|
||||
|
||||
#+NAME: sprint-names-2022
|
||||
- ankheg
|
||||
- beholder
|
||||
- centaur
|
||||
- dragon
|
||||
- elf
|
||||
- fetch
|
||||
- goblin
|
||||
- hydra
|
||||
- illythid
|
||||
- jackalwere
|
||||
- kobold
|
||||
- lich
|
||||
- mimic
|
||||
- nymph
|
||||
- owlbear
|
||||
- pegasus
|
||||
- quasit
|
||||
- remorhaz
|
||||
- satyr
|
||||
- troll
|
||||
- unicorn
|
||||
- vampire
|
||||
- warg
|
||||
- xorn
|
||||
- yuan-ti
|
||||
- zombie
|
||||
** 2021
|
||||
Choosing Sprint Names based on [[https://www.imagineforest.com/blog/funniest-words-in-the-english-language/][Funny or Silly Words]]:
|
||||
|
||||
#+NAME: sprint-names-2021
|
||||
- abibliophobia :: The fear of running out of reading materials to read
|
||||
- bamboozled :: To trick or confuse someone
|
||||
- catawampus :: Something positioned diagonally
|
||||
- dweeb :: A boring and uninteresting person
|
||||
- eep :: Another expression of surprise or fear.
|
||||
- formication :: The feeling that ants are crawling on your skin.
|
||||
- goombah :: An older friend who protects you.
|
||||
- hootenanny :: A country music party or get-together.
|
||||
- Izzat :: This relates to your personal respect and dignity.
|
||||
- jabberwock :: Something that is complete nonsense or gibberish
|
||||
- kebbie :: A Scottish term relating to a walking stick with a hooked end.
|
||||
- lollygagger :: Someone who walks around with no aim or goal.
|
||||
- mollycoddle :: To be extra nice to someone or to overprotect them.
|
||||
- nacket :: A light lunch or snack.
|
||||
- obi :: A sash worn around the waist of a kimono
|
||||
- panjandrum :: Someone who thinks that they are superior to others.
|
||||
- quoz :: Something that is strange.
|
||||
- ratoon :: The small root that sprouts from a plant, especially during the springtime.
|
||||
- sialoquent :: Someone who splits while talking.
|
||||
- taradiddle :: this is a small lie or when someone is speaking nonsense.
|
||||
- urubu :: A blank vulture found in South American.
|
||||
- vamp :: To make something brand-new.
|
||||
- wabbit :: A Scottish word referring to feeling exhausted or a little unwell.
|
||||
- xanthoderm :: A person with yellowish skin.
|
||||
- yerk :: Pull or push something with a sudden movement.
|
||||
- zazzy :: Something that is shiny and flashy
|
||||
** 2020
|
||||
|
||||
New names from [[https://en.m.wikipedia.org/wiki/List_of_dinosaur_genera][list of dinosaurs]].
|
||||
|
||||
#+NAME: sprint-names-2020
|
||||
- ankylosaurus
|
||||
- brontosaurus
|
||||
- coelophysis
|
||||
- diplodocus
|
||||
- eoraptor
|
||||
- fruitadens
|
||||
- gobiceratops
|
||||
- harpymimus
|
||||
- iguanodozn
|
||||
- jinfengopteryx
|
||||
- kentrosaurus
|
||||
- lambeosaurus
|
||||
- maiasaura
|
||||
- neimongosaurus
|
||||
- oviraptor
|
||||
- pachycephalosaurus
|
||||
- quetzalcoatlus
|
||||
- rioarribasaurus
|
||||
- stegosaurus
|
||||
- tyrannosaurus
|
||||
- utahraptor
|
||||
- velociraptor
|
||||
- wannanosaurus
|
||||
- xiaotingia
|
||||
- yi
|
||||
- zuul
|
||||
|
||||
** 2019
|
||||
|
||||
Came up with a list of somewhat well-known cities throughout the world (at least, they had to have a population of 100,000 or more), but I didn't want any real obvious ones.
|
||||
|
||||
#+NAME: sprint-names-2019
|
||||
- achy-aachen
|
||||
- bare-bacabal
|
||||
- candid-cannes
|
||||
- darling-dadu
|
||||
- easy-edmonton
|
||||
- fancy-fargo
|
||||
- gray-gaya
|
||||
- handsome-hanoi
|
||||
- itchy-incheon
|
||||
- jumpy-juba
|
||||
- kind-kindia
|
||||
- less-liling
|
||||
- mad-madrid
|
||||
- natural-naga
|
||||
- octarine-oakland
|
||||
- painful-paris
|
||||
- quirky-qufu
|
||||
- rabid-rabat
|
||||
- slow-slough
|
||||
- typing-taipei
|
||||
- ugly-ufa
|
||||
- vibrant-vienna
|
||||
- wacky-waco
|
||||
- xenophobic-xichang
|
||||
- yellow-yamaguchi
|
||||
- zippy-zinder
|
||||
|
||||
* Sprint Boundaries
|
||||
Function to help in calculating dates and other features of a two-week sprint that starts on Thursday and ends on a Wednesday...hey, that is just how we do things at my job.
|
||||
|
||||
Emacs have an internal rep of a time.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun get-date-time (date)
|
||||
"Many functions can't deal with dates as string, so this will
|
||||
parse DATE if it is a string, or return the value given otherwise."
|
||||
(if (stringp date)
|
||||
(->> date ; Shame that encode-time
|
||||
parse-time-string ; can't take a string, as
|
||||
(-take 6) ; this seems excessive...
|
||||
(--map (if (null it) 0 it))
|
||||
(apply 'encode-time))
|
||||
date))
|
||||
#+END_SRC
|
||||
|
||||
** Sprint Numbering
|
||||
|
||||
My Sprint starts on Thursday, but this sometimes changed, so let's make this a variable:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defvar sprint-starting-day 2 "The day of the week the sprint begins, where 0 is Sunday.")
|
||||
#+END_SRC
|
||||
|
||||
We label our sprint based on the week number that it starts. However, on a Monday, I want to consider that we are still numbering from last week.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun sprint-week-num (&optional date)
|
||||
"Return the week of the current year (or DATE), but starting
|
||||
the week at Thursday to Wednesday."
|
||||
(let* ((d (get-date-time date))
|
||||
(dow (nth 6 (decode-time d))) ; Day of the week 0=Sunday
|
||||
(week (->> d ; Week number in the year
|
||||
(format-time-string "%U")
|
||||
string-to-number)))
|
||||
(if (>= dow sprint-starting-day)
|
||||
(1+ week)
|
||||
week)))
|
||||
#+END_SRC
|
||||
|
||||
Let's have a few tests to make sure, and yeah, perhaps we update this at the beginning of each year.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp :tangle no
|
||||
(ert-deftest sprint-week-num-test ()
|
||||
(should (= (sprint-week-num "2021-03-15") 11)) ;; Monday previous week
|
||||
(should (= (sprint-week-num "2021-03-16") 12)) ;; Tuesday current week
|
||||
(should (= (sprint-week-num "2021-03-19") 12)))
|
||||
#+END_SRC
|
||||
|
||||
Since my sprints are currently two weeks long, we could be see that on even week numbers, the /sprint/ is actually the previous week's number.
|
||||
|
||||
And it appears that my PM for this year, is a week number behind.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun sprint-number (&optional date)
|
||||
"Return the current sprint number, with some assumptions that
|
||||
each sprint is two weeks long, starting on Thursday."
|
||||
(interactive)
|
||||
(let ((num (sprint-week-num date)))
|
||||
(if (oddp num)
|
||||
(- num 2)
|
||||
(- num 1))))
|
||||
#+END_SRC
|
||||
|
||||
And some tests to verify that:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp :tangle no
|
||||
(ert-deftest sprint-number-test ()
|
||||
(should (= (sprint-number "2021-03-15") 9))
|
||||
(should (= (sprint-number "2021-03-16") 11))
|
||||
(should (= (sprint-number "2021-03-22") 11))
|
||||
(should (= (sprint-number "2021-03-23") 11))
|
||||
(should (= (sprint-number "2021-03-29") 11))
|
||||
(should (= (sprint-number "2021-03-30") 13)))
|
||||
#+END_SRC
|
||||
** Sprint File Name
|
||||
|
||||
I create my org-file notes based on the Sprint number.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun sprint-current-file (&optional date)
|
||||
"Return the absolute pathname to the current sprint file."
|
||||
(let ((d (get-date-time date)))
|
||||
(expand-file-name
|
||||
(format "~/Notes/Sprint-%s-%02d.org"
|
||||
(format-time-string "%Y" d)
|
||||
(sprint-number d)))))
|
||||
#+END_SRC
|
||||
|
||||
So what that means, is given a particular date, I should expect to be able to find the correct Sprint file name:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp :tangle no
|
||||
(ert-deftest sprint-current-file-test ()
|
||||
(should (s-ends-with? "Sprint-2019-05.org" (sprint-current-file "2019-02-07")))
|
||||
(should (s-ends-with? "Sprint-2019-05.org" (sprint-current-file "2019-02-09")))
|
||||
(should (s-ends-with? "Sprint-2019-05.org" (sprint-current-file "2019-02-10")))
|
||||
(should (s-ends-with? "Sprint-2019-05.org" (sprint-current-file "2019-02-13")))
|
||||
(should (s-ends-with? "Sprint-2019-07.org" (sprint-current-file "2019-02-14")))
|
||||
(should (s-ends-with? "Sprint-2019-07.org" (sprint-current-file "2019-02-17"))))
|
||||
#+END_SRC
|
||||
|
||||
Daily note-taking goes into my sprint file notes, so this interactive function makes an easy global short-cut key.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun sprint-current-find-file (&optional date)
|
||||
"Load the `org-mode' note associated with my current sprint."
|
||||
(interactive)
|
||||
(find-file (sprint-current-file date)))
|
||||
#+END_SRC
|
||||
|
||||
The /name/ and /nickname/ of the sprint will be used in the =#+TITLE= section, and it looks something like: =Sprint 2019-07 (darling-dadu)=
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun sprint-current-name (&optional date)
|
||||
"Return the default name of the current sprint (based on DATE)."
|
||||
(let* ((d (get-date-time date))
|
||||
(sprint-order (/ (1- (sprint-number d)) 2))
|
||||
(nickname (nth sprint-order sprint-nicknames)))
|
||||
(format "Sprint %s-%02d %s"
|
||||
(format-time-string "%Y" d)
|
||||
(sprint-number d)
|
||||
nickname)))
|
||||
#+END_SRC
|
||||
|
||||
These test won't pass any more, as the nickname of the sprint changes from year to year.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp :tangle no
|
||||
(ert-deftest sprint-current-name-test ()
|
||||
(should (equal "Sprint 2019-05 (candid-cannes)" (sprint-current-name "2019-02-13")))
|
||||
(should (equal "Sprint 2019-07 (darling-dadu)" (sprint-current-name "2019-02-14"))))
|
||||
#+END_SRC
|
||||
|
||||
** Sprint Start and End
|
||||
|
||||
I want to print the beginning and ending of the sprint, where we have a sprint number or a data, and we can give the dates that bound the sprint. This odd function calculates this based on knowing the date of the /first thursday/ of the year, so I need to begin the year changing this value. I should fix this.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun sprint-range (&optional number-or-date)
|
||||
"Return a list of three entries, start of the current sprint,
|
||||
end of the current sprint, and the start of the next sprint.
|
||||
Each date value should be formatted with `format-time-string'."
|
||||
(let* ((num (if (or (null number-or-date) (stringp number-or-date))
|
||||
(sprint-number number-or-date)
|
||||
number-or-date))
|
||||
(year-start "2020-01-02") ; First Thursday of the year
|
||||
(time-start (-> year-start ; Converted to time
|
||||
get-date-time
|
||||
float-time))
|
||||
(day-length (* 3600 24)) ; Length of day in seconds
|
||||
(week-length (* day-length 7))
|
||||
(sprint-start (time-add time-start (* week-length (1- num))))
|
||||
(sprint-next (time-add time-start (* week-length (1+ num))))
|
||||
(sprint-end (time-add sprint-next (- day-length))))
|
||||
(list sprint-start sprint-end sprint-next)))
|
||||
#+END_SRC
|
||||
|
||||
Format the start and end so that we can insert this directly in the org file:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun sprint-date-range (&optional number-or-date)
|
||||
"Return an `org-mode' formatted date range for a given sprint
|
||||
number or date, `NUMBER-OR-DATE' or if `nil', the date range of
|
||||
the current sprint."
|
||||
(seq-let (sprint-start sprint-end) (sprint-range number-or-date)
|
||||
(let* ((formatter "%Y-%m-%d %a")
|
||||
(start (format-time-string formatter sprint-start))
|
||||
(end (format-time-string formatter sprint-end)))
|
||||
(format "[%s]--[%s]" start end))))
|
||||
#+END_SRC
|
||||
|
||||
And let's have a test to validate this:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(ert-deftest sprint-date-range ()
|
||||
(should (equal (sprint-date-range 7)
|
||||
(sprint-date-range "2020-02-17"))))
|
||||
#+END_SRC
|
||||
|
||||
** Pre-scheduled Dates
|
||||
|
||||
Due to the regularity of the sprint cadence, I can pre-schedule meetings and other deadlines by /counting/ the number of days from the start of the sprint:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun sprint-date-from-start (days &optional formatter)
|
||||
"Given a number of DAYS from the start of the sprint, return a formatted date string."
|
||||
(let* ((day-length (* 3600 24))
|
||||
(start (car (sprint-range)))
|
||||
(adate (time-add start (* day-length days))))
|
||||
(if formatter
|
||||
(format-time-string formatter adate)
|
||||
(format-time-string "%Y-%m-%d %a" adate))))
|
||||
#+END_SRC
|
||||
|
||||
* Other Date Functions
|
||||
|
||||
The following functions /were/ helpful at times. But I'm not sure I will use them.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp :tangle no
|
||||
(defun sprint-num-days (time-interval)
|
||||
"Converts a TIME-INTERVAL to a number of days."
|
||||
(let ((day-length (* 3600 24)))
|
||||
(round (/ (float-time time-interval) day-length))))
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC emacs-lisp :tangle no
|
||||
(defun sprint-day-range (&optional date)
|
||||
"Returns a list of two values, the number of days from the
|
||||
start of the sprint, and the number of days to the end of the
|
||||
sprint based on DATE if given, or from today if DATE is `nil'."
|
||||
(seq-let (sprint-start sprint-end) (sprint-range date)
|
||||
(let* ((now (get-date-time date))
|
||||
(starting (time-subtract sprint-start now))
|
||||
(ending (time-subtract sprint-end now)))
|
||||
(list (sprint-num-days starting) (sprint-num-days ending)))))
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC emacs-lisp :tangle no
|
||||
(ert-deftest sprint-day-range ()
|
||||
;; This sprint starts on 2/13 and ends on 2/26
|
||||
(should (equal '(0 13) (sprint-day-range "2020-02-13")))
|
||||
(should (equal '(-1 12) (sprint-day-range "2020-02-14")))
|
||||
(should (equal '(-13 0) (sprint-day-range "2020-02-26"))))
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC emacs-lisp :tangle no
|
||||
(defun sprint-day-start (&optional date)
|
||||
"Return a relative number of days to the start of the current sprint. For instance, if today was Friday, and the sprint started on Thursday, this would return -1."
|
||||
(first (sprint-day-range date)))
|
||||
|
||||
(defun sprint-day-end (&optional date)
|
||||
"Return a relative number of days to the end of the current sprint. For instance, if today was Monday, and the sprint will end on Wednesday, this would return 3."
|
||||
(second (sprint-day-range date)))
|
||||
#+END_SRC
|
||||
|
||||
* Technical Artifacts :noexport:
|
||||
|
||||
Let's provide a name so that the file can be required:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp :exports none
|
||||
(provide 'ha-org-sprint)
|
||||
;;; ha-org-sprint.el ends here
|
||||
#+END_SRC
|
||||
|
||||
Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: ~C-c C-c~
|
||||
|
||||
#+DESCRIPTION: A literate program for configuring org files for work-related notes.
|
||||
|
||||
#+PROPERTY: header-args:sh :tangle no
|
||||
#+PROPERTY: header-args:emacs-lisp yes
|
||||
#+PROPERTY: header-args :results none :eval no-export :comments no mkdirp yes
|
||||
|
||||
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil date:nil
|
||||
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
|
||||
#+INFOJS_OPT: view:nil toc:nil ltoc:t mouse:underline buttons:0 path:http://orgmode.org/org-info.js
|
18
ha-org.org
18
ha-org.org
|
@ -241,10 +241,24 @@ Of course, I need an 'undo' feature when the meeting is over...
|
|||
Whenever I edit Emacs Lisp blocks from my tangle-able configuration files, I get a lot of superfluous warnings. Let's turn them off.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun disable-fylcheck-in-org-src-block ()
|
||||
(defun disable-flycheck-in-org-src-block ()
|
||||
(setq-local flycheck-disabled-checkers '(emacs-lisp-checkdoc)))
|
||||
|
||||
(add-hook 'org-src-mode-hook 'disable-fylcheck-in-org-src-block)
|
||||
(add-hook 'org-src-mode-hook 'disable-flycheck-in-org-src-block)
|
||||
#+END_SRC
|
||||
And turn on ALL the languages:
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(org-babel-do-load-languages 'org-babel-load-languages
|
||||
'((shell . t)
|
||||
(js . t)
|
||||
(emacs-lisp . t)
|
||||
(clojure . t)
|
||||
(python . t)
|
||||
(ruby . t)
|
||||
(dot . t)
|
||||
(css . t)
|
||||
(plantuml . t)))
|
||||
|
||||
#+END_SRC
|
||||
*** Next Image
|
||||
When I create images or other artifacts that I consider /part/ of the org document, I want to have them based on the org file, but with a prepended number. Keeping track of what numbers are now free is difficult, so for a /default/ let's figure it out:
|
||||
|
|
Loading…
Reference in a new issue