Compare commits
11 commits
e40c57ff18
...
bba1e52a06
Author | SHA1 | Date | |
---|---|---|---|
|
bba1e52a06 | ||
|
e36ae58ae0 | ||
|
1ecf9aa6a2 | ||
|
df7f423924 | ||
|
0c69fd7a8f | ||
|
c38243eb0a | ||
|
5ac74fadce | ||
|
f5cfc64d41 | ||
|
5ce9c25249 | ||
|
f40932c5de | ||
|
dcd050b37a |
18 changed files with 618 additions and 367 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -9,3 +9,4 @@
|
|||
/elisp/gourmet.el
|
||||
/elisp/wd-imaas.el
|
||||
/ha-theme-results.org
|
||||
/support/dashboard
|
|
@ -33,7 +33,8 @@ Customize the variable, `beep-alert-sound-file' to adjust the sound."
|
|||
"Call a program to speak the string, PHRASE.
|
||||
Customize the variable, `beep-speech-executable'."
|
||||
(let ((command (format beep-speech-executable phrase)))
|
||||
(async-shell-command command)))
|
||||
(save-window-excursion
|
||||
(async-shell-command command))))
|
||||
|
||||
(defun beep-when-finished (phrase &optional to-speak)
|
||||
"Notify us with string, PHRASE, to grab our attention.
|
||||
|
|
|
@ -84,31 +84,47 @@ Can not live without [[https://magit.vc/][Magit]], a Git porcelain for Emacs. I
|
|||
|
||||
(general-nmap "<escape>" #'transient-quit-one))
|
||||
#+end_src
|
||||
** Git Gutter
|
||||
The [[https://github.com/syohex/emacs-git-gutter-fringe][git-gutter-fringe]] project displays markings in the fringe (extreme left margin) to show modified and uncommitted lines. This project builds on [[https://github.com/emacsorphanage/git-gutter][git-gutter]] project to provide movement between /hunks/:
|
||||
#+begin_src emacs-lisp
|
||||
(use-package git-gutter-fringe
|
||||
** VC Diff Highlight
|
||||
The [[https://github.com/dgutov/diff-hl][diff-hl project]], while more active, has more features than the [[https://github.com/syohex/emacs-git-gutter-fringe][git-gutter-fringe]] project.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(use-package diff-hl
|
||||
:custom
|
||||
;; To have both flymake and git-gutter work, we put
|
||||
;; git-gutter on the right side:
|
||||
(git-gutter-fr:side 'right-fringe)
|
||||
;; (left-fringe-width 15)
|
||||
(right-fringe-width 10)
|
||||
(diff-hl-side 'right)
|
||||
(fringe-mode '(8 . 4))
|
||||
(diff-hl-draw-borders nil)
|
||||
|
||||
:hook ((dired-mode . diff-hl-dired-mode)
|
||||
(diff-hl-mode . diff-hl-flydiff-mode)))
|
||||
#+END_SRC
|
||||
|
||||
Turning on the mode, as well as binding some new /leader/ keys:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(use-package diff-hl
|
||||
:config
|
||||
(set-face-foreground 'git-gutter-fr:modified "yellow")
|
||||
(set-face-foreground 'git-gutter-fr:added "green")
|
||||
(set-face-foreground 'git-gutter-fr:deleted "red")
|
||||
|
||||
(global-git-gutter-mode)
|
||||
(global-diff-hl-mode)
|
||||
|
||||
(ha-leader
|
||||
"g n" '("next hunk" . git-gutter:next-hunk)
|
||||
"g p" '("previous hunk" . git-gutter:previous-hunk)
|
||||
"g e" '("end of hunk" . git-gutter:end-of-hunk)
|
||||
"g r" '("revert hunk" . git-gutter:revert-hunk)
|
||||
"g s" '("stage hunk" . git-gutter:stage-hunk)))
|
||||
#+end_src
|
||||
"g j" '("jump hunk" . diff-hl-diff-goto-hunk)
|
||||
"g ]" '("next hunk" . diff-hl-next-hunk)
|
||||
"g [" '("previous hunk" . diff-hl-previous-hunk)
|
||||
"g e" '("end of hunk" . diff-hl-end-of-hunk)
|
||||
"g r" '("revert hunk" . diff-hl-revert-hunk)
|
||||
"g s" '("show hunk" . diff-hl-show-hunk)
|
||||
"g S" '("stage hunk" . diff-hl-stage-dwim)
|
||||
|
||||
;; Using Gerrit means I might want to view changes not from my
|
||||
;; last review, but from the original changes:
|
||||
"g a" '("diff amend" . diff-hl-amend-mode)))
|
||||
#+END_SRC
|
||||
|
||||
This project (and others) can use repeat mode, but
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(repeat-mode)
|
||||
#+END_SRC
|
||||
|
||||
** Git Delta
|
||||
The [[https://scripter.co/using-git-delta-with-magit][magit-delta]] project uses [[https://github.com/dandavison/delta][git-delta]] for colorized diffs.
|
||||
#+begin_src emacs-lisp
|
||||
|
@ -264,6 +280,8 @@ What's left is integrating the new show and diff commands in Magit. For that pur
|
|||
|
||||
(ha-leader "g d" '("difftastic" . ha-difftastic-here))
|
||||
#+end_src
|
||||
|
||||
How much has been already integrated? Need to re-evaluate this.
|
||||
** Time Machine
|
||||
The [[https://github.com/emacsmirror/git-timemachine][git-timemachine]] project visually shows how a code file changes with each iteration:
|
||||
#+begin_src emacs-lisp
|
||||
|
@ -393,6 +411,8 @@ Web pages look pretty good with EWW, but I'm having difficulty getting it to ren
|
|||
:init
|
||||
(setq browse-url-browser-function 'eww-browse-url
|
||||
browse-url-secondary-browser-function 'browse-url-default-browser
|
||||
browse-url-chrome-program "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
|
||||
|
||||
eww-browse-url-new-window-is-tab nil
|
||||
shr-use-colors nil
|
||||
shr-use-fonts t ; I go back and forth on this one
|
||||
|
|
|
@ -147,10 +147,11 @@ The venerable [[https://github.com/hayamiz/twittering-mode/tree/master][twitteri
|
|||
And we are no longer using this package.
|
||||
** Telega
|
||||
I'm thinking the [[https://zevlg.github.io/telega.el/][Telega package]] would be better than Bitlbee for Telegram communication.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(use-package telega
|
||||
:config
|
||||
(setq telega-user-use-avatars nil
|
||||
(setq telega-chat-show-avatars nil
|
||||
telega-use-tracking-for nil ; '(any pin unread)
|
||||
;; Use org formatting for normal messages.
|
||||
;; Want to send the org markup without formatting?
|
||||
|
|
|
@ -41,14 +41,16 @@ I like the rendering of curved quotes using [[help:text-quoting-style][text-quot
|
|||
#+end_src
|
||||
When typing prose in Org documents, I need to [[file:ha-org-word-processor.org::*Typographic Quotes][do something else]] for rounded quotes and ellipsis.
|
||||
|
||||
Changes and settings I like introduced that were introduced in Emacs 28:
|
||||
Changes and settings I like introduced in Emacs 28:
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(setq use-short-answers t
|
||||
describe-bindings-outline t
|
||||
completions-detailed t)
|
||||
#+end_src
|
||||
|
||||
I’ve got preferences for how I like scrolling, and with my org files, I need a little more of the of the context, so this increases from =2= to =3=, but I really like to keep the cursor in place when I can:
|
||||
I’ve got preferences for how I like scrolling, and with my org files, I need a little more of the of the context, so this increases from =2= to =3=, but I like to keep the cursor in place when I can:
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(setq next-screen-context-lines 3
|
||||
scroll-error-top-bottom t
|
||||
|
@ -139,7 +141,7 @@ After reading [[https://irreal.org/blog/?p=12139][Jon Sander’s essay]] as well
|
|||
:straight (:host github :repo "tecosaur/emacs-everywhere"))
|
||||
#+end_src
|
||||
|
||||
This package is /called outside of Emacs/, so I bound a keybinding to iCanHazShortcut:
|
||||
This package /called outside of Emacs/, so I bound a keybinding to iCanHazShortcut:
|
||||
|
||||
#+begin_src sh
|
||||
emacsclient --socket-name personal --eval "(emacs-everywhere)"
|
||||
|
@ -619,8 +621,9 @@ As I've mentioned [[http://www.howardism.org/Technical/Emacs/beep-for-emacs.html
|
|||
'libnotify)))
|
||||
|
||||
(use-package beep
|
||||
:straight nil ; Already in the load-path
|
||||
:hook (after-init . (lambda () (beep-when-finished "Emacs has started." "Eemacs has started")))
|
||||
:straight (:local-repo "~/src/hamacs/elisp")
|
||||
:hook (after-init . ha-random-startup-message)
|
||||
:commands (beep-when-finished beep-when-run-too-long)
|
||||
:config
|
||||
(dolist (func '(org-publish
|
||||
org-publish-all
|
||||
|
@ -628,9 +631,19 @@ As I've mentioned [[http://www.howardism.org/Technical/Emacs/beep-for-emacs.html
|
|||
compile
|
||||
shell-command))
|
||||
(advice-add func :around #'beep-when-runs-too-long)))
|
||||
|
||||
(defun ha-random-startup-message ()
|
||||
"State a random message on startup."
|
||||
(let ((msg (seq-random-elt '("You are good to go"
|
||||
"Yippee"
|
||||
"What's next?"
|
||||
"Notification complete. Happy?"
|
||||
"Beware lest the dragons fly"))))
|
||||
(beep-when-finished msg)))
|
||||
#+end_src
|
||||
|
||||
While that code /advices/ the publishing and compile commands, I may want to add more.
|
||||
**** Visual Replacing Regular Expressions
|
||||
*** Visual Replacing Regular Expressions
|
||||
I appreciated the [[https://github.com/benma/visual-regexp.el][visual-regexp package]] to see what you want to change /before/ executing the replace.
|
||||
#+begin_src emacs-lisp
|
||||
(use-package visual-regexp
|
||||
|
@ -671,7 +684,7 @@ Now we just need to filter the results from the built-in Emacs function:
|
|||
#+begin_src emacs-lisp
|
||||
(advice-add 'read-regexp :filter-return 'read-regexp-with-rx)
|
||||
#+end_src
|
||||
**** Jump with Avy
|
||||
*** Jump with Avy
|
||||
While I grew up on =Control S=, I am liking the /mental model/ associated with the [[https://github.com/abo-abo/avy][avy project]] that allows a /jump/ among matches across all visible windows. I use the ~F18~ key on my keyboard that should be easy to use, but ~g o~ seems obvious.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
|
@ -709,7 +722,7 @@ If you hit the following keys /before/ you select a target, you get special acti
|
|||
I’m not thinking of ideas of what would be useful, e.g. ~v~ to highlight from cursor to target, etc.
|
||||
|
||||
Want to know something amazing. In a Terminal, like =vterm= or =eshell=, I run ~s-g~ and pinpoint the UUID in the output of a long command. Then type ~y~ and then ~C-y~ to paste that ID without even moving the mouse.
|
||||
**** Link Hint, the Link Jumper
|
||||
*** Link Hint, the Link Jumper
|
||||
The [[info:emacs#Goto Address mode][Goto Address]] mode (see this [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Goto-Address-mode.html][online link]]) turns URLs into clickable links. Nice feature and built into Emacs, but it requires using the mouse or moving to the URL and hitting ~Return~ (if you like this idea, check out [[https://xenodium.com/actionable-urls-in-emacs-buffers/][Álvaro Ramírez's configuration]] for this).
|
||||
|
||||
I appreciated [[https://github.com/abo-abo/ace-link][ace-link]]’s idea for hyperlinks on Org, EWW and Info pages, as it allowed you to jump to a URL from any location on the screen. The [[https://github.com/noctuid/link-hint.el][link-hint]] project does this, but works with more types of files and links:
|
||||
|
@ -739,7 +752,7 @@ Can I open a link in another window? The idea with this is that I can select a l
|
|||
(ace-select-window)
|
||||
(eww (current-kill 0)))
|
||||
#+end_src
|
||||
**** Expand Region
|
||||
*** Expand Region
|
||||
Magnar Sveen's [[https://github.com/magnars/expand-region.el][expand-region]] project allows me to hit ~v~ in =visual= mode, and have the selection grow by syntactical units.
|
||||
#+begin_src emacs-lisp
|
||||
(use-package expand-region
|
||||
|
@ -752,7 +765,7 @@ Magnar Sveen's [[https://github.com/magnars/expand-region.el][expand-region]] pr
|
|||
"V" 'er/contract-region
|
||||
"-" 'er/contract-region))
|
||||
#+end_src
|
||||
**** iSearch
|
||||
*** iSearch
|
||||
The built-in =isearch= is fantastically simple and useful, but the [[https://github.com/kickingvegas/cc-isearch-menu][cc-isearch-menu]] helps expose some /buried/ features.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
|
@ -901,6 +914,7 @@ The /special/ perspective is a nice shortcut to the one I use the most:
|
|||
#+end_src
|
||||
|
||||
I often want a workspace dedicated to an /application/, so this function:
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(defun ha-app-perspective (name func)
|
||||
(lambda ()
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#+title: Start Screen
|
||||
#+author: Howard Abrams
|
||||
#+date: 2022-11-02
|
||||
#+tags: emacs
|
||||
#+TITLE: Start Screen
|
||||
#+AUTHOR: Howard Abrams
|
||||
#+DATE: 2022-11-02
|
||||
#+TAGS: emacs
|
||||
|
||||
A literate programming file for configuring Emacs to show a startup screen.
|
||||
|
||||
|
@ -139,7 +139,11 @@ The [[https://github.com/emacs-dashboard/emacs-dashboard][emacs-dashboard]] proj
|
|||
(native-comp-available-p))
|
||||
"with Native Compilation" "")
|
||||
(ha-dashboard-version))
|
||||
dashboard-startup-banner "~/src/hamacs/support/levitating-gnu.png"
|
||||
|
||||
;; Choose a random image from my collection of startup images:
|
||||
dashboard-startup-banner (thread-first "~/src/hamacs/support/dashboard"
|
||||
(directory-files t (rx ".png"))
|
||||
(seq-random-elt))
|
||||
dashboard-center-content t
|
||||
dashboard-set-init-info t
|
||||
dashboard-projects-switch-function 'project-switch-project
|
||||
|
|
679
ha-demos.org
679
ha-demos.org
|
@ -1,8 +1,8 @@
|
|||
#+title: Demonstrations in Emacs
|
||||
#+author: Howard X. Abrams
|
||||
#+date: 2024-10-18
|
||||
#+filetags: emacs hamacs
|
||||
#+lastmod: [2024-12-16 Mon]
|
||||
#+TITLE: Demonstrations in Emacs
|
||||
#+AUTHOR: Howard X. Abrams
|
||||
#+DATE: 2024-10-18
|
||||
#+FILETAGS: emacs hamacs
|
||||
#+LASTMOD: [2025-01-14 Tue]
|
||||
#+STARTUP: showstars
|
||||
|
||||
A literate programming file for creating and running demonstrations
|
||||
|
@ -59,6 +59,156 @@ But I feel I should replace it, and this project encapsulates the following goal
|
|||
|
||||
* Presentations with Org
|
||||
A demonstration begins with an Org file where the screen shows a /single heading/ with a larger font. Not much more. I’m playing around with /all/ the projects available, including writing my own.
|
||||
** My Slides
|
||||
A /full/ presentation requires my /notes/ on one frame, and the presentation on the other.
|
||||
|
||||
To use this, following:
|
||||
1. Select the Org mode presentation
|
||||
2. Run the function, =ha-slide-make-notes-frame=
|
||||
3. Reference the notes file associated with the presentation
|
||||
|
||||
The end result is two frames, where updating the presentation, updates the location of the other frame to match the same headline.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(defvar ha-slide-notes-frame-name "Demonstration Notes"
|
||||
"The name of the frame that displays the presentation notes.")
|
||||
|
||||
(defvar ha-slide-notes-frame nil
|
||||
"Frame containing the presentation notes.")
|
||||
|
||||
(defvar ha-slide-notes-window nil
|
||||
"Window containing the presentation notes.")
|
||||
|
||||
(defun ha-slide-make-notes-frame (filename &optional heading)
|
||||
"Display the notes, FILENAME, in a new frame.
|
||||
With HEADING, jump to that `org-mode' headline."
|
||||
(interactive "fNotes File: ")
|
||||
(let ((f (selected-frame)))
|
||||
(setq ha-slide-notes-frame
|
||||
(make-frame `((name . ,ha-slide-notes-frame-name))))
|
||||
(set-frame-position ha-slide-notes-frame 1310 0)
|
||||
(set-frame-size ha-slide-notes-frame 920 1420 t)
|
||||
|
||||
;; While I could call `find-file-other-frame', I want to make
|
||||
;; sure I get the file loaded in the correct frame:
|
||||
(x-focus-frame ha-slide-notes-frame)
|
||||
(find-file filename)
|
||||
(goto-char (point-min))
|
||||
(when heading
|
||||
(re-search-forward (rx bol (one-or-more "*") (one-or-more space) (literal heading)))
|
||||
(recenter-top-bottom 0))
|
||||
|
||||
(setq ha-slide-notes-window (selected-window))
|
||||
(delete-other-windows)
|
||||
|
||||
;; Highlight the original window containing the presentation:
|
||||
(x-focus-frame f)))
|
||||
#+end_src
|
||||
|
||||
These interactive functions scroll the “notes” in the other window in another frame:
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(defun ha-slide-notes-scroll-up ()
|
||||
"Scroll the frame/window containing the notes, up."
|
||||
(interactive)
|
||||
(when ha-slide-notes-window
|
||||
(with-selected-window ha-slide-notes-window
|
||||
(scroll-up -10))))
|
||||
|
||||
(defun ha-slide-notes-scroll-down ()
|
||||
"Scroll the frame/window containing the notes, down."
|
||||
(interactive)
|
||||
(when ha-slide-notes-window
|
||||
(with-selected-window ha-slide-notes-window
|
||||
(scroll-up 10))))
|
||||
|
||||
(defun ha-slide-notes-update ()
|
||||
"Function to move the notes headline to current buffers.
|
||||
Assuming the buffer is showing an org-file, and have
|
||||
called `ha-slide-make-notes-frame', this function moves
|
||||
the point in that buffer to the same headline."
|
||||
(interactive)
|
||||
(when ha-slide-notes-window
|
||||
(let ((heading (thread-first
|
||||
(org-get-heading t t t t)
|
||||
(substring-no-properties))))
|
||||
(with-selected-window ha-slide-notes-window
|
||||
(goto-char (point-min))
|
||||
(re-search-forward (rx (literal heading)) nil t)
|
||||
(recenter-top-bottom 0)))))
|
||||
#+end_src
|
||||
|
||||
Call the =ha-slide-notes-update= function automatically after updating a slide. With =dslide=, we add a hook:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(use-package dslide
|
||||
:straight (dslide :host github :repo "positron-solutions/dslide")
|
||||
:commands (dslide-narrow-hook)
|
||||
:hook (dslide-narrow . 'ha-slide-notes-update))
|
||||
#+END_SRC
|
||||
|
||||
** My Presentation View
|
||||
Regardless of the presentation package I use, I make them all look similar with the following code. Much of this is getting rid of Emacs visual elements, like the cursor and the mode-line, as well as stopping minor modes that add visual changes, like spellchecking and the gutter. I can call this function from any presentation software used.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun ha-slide-setup (&optional frame-name)
|
||||
"Configure the look I want for presentations.
|
||||
The frame associated with FRAME-NAME is tidied
|
||||
by removing the gutters and other informative
|
||||
widgets not needed for a presentation."
|
||||
(org-indent-mode -1)
|
||||
;; (org-modern-mode -1)
|
||||
|
||||
(setq org-image-actual-width nil)
|
||||
(org-display-inline-images)
|
||||
(ha-org-blocks-hide-headers)
|
||||
(ha-org-hide-stars)
|
||||
(font-lock-update)
|
||||
(ha-demo-hide-mode-line)
|
||||
(ha-demo-hide-cursor)
|
||||
(ha-demo-presentation-frame frame-name)
|
||||
|
||||
(text-scale-set 4)
|
||||
(diff-hl-mode -1)
|
||||
(flycheck-mode -1)
|
||||
(jinx-mode -1)
|
||||
|
||||
;; Clear the demonstration state cache:
|
||||
(clrhash ha-demo-prev-state)
|
||||
|
||||
(evil-normal-state))
|
||||
#+END_SRC
|
||||
|
||||
And after a presentation finishes, this function cleans up by restoring minor modes, etc:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun ha-slide-teardown ()
|
||||
"Reset the Org after a presentation."
|
||||
(org-indent-mode 1)
|
||||
;; (org-modern-mode 1)
|
||||
|
||||
(ha-org-blocks-show-headers)
|
||||
(font-lock-update)
|
||||
(ha-demo-show-mode-line)
|
||||
(ha-demo-show-cursor)
|
||||
(ha-demo-normalize-frame)
|
||||
|
||||
(text-scale-set 0)
|
||||
(diff-hl-mode)
|
||||
(flycheck-mode)
|
||||
(jinx-mode))
|
||||
#+END_SRC
|
||||
|
||||
The =dslide= seems to reset /everything/ on each slide display, so:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun ha-slide-reset ()
|
||||
"Reset the current slide."
|
||||
(interactive)
|
||||
(ha-org-blocks-hide-headers)
|
||||
(font-lock-update))
|
||||
#+END_SRC
|
||||
|
||||
** Org Tree Slide
|
||||
I’ve used [[https://github.com/takaxp/org-tree-slide][org-tree-slide]] for years for showing org files as presentations. I like the /simple/ presentation and it seems to shows all the images.
|
||||
|
||||
|
@ -129,8 +279,8 @@ The [[https://github.com/positron-solutions/dslide][dslide project]] is flexible
|
|||
|
||||
#+begin_src emacs-lisp
|
||||
(use-package dslide
|
||||
:straight (dslide :type git :host github :repo "positron-solutions/dslide")
|
||||
|
||||
:straight (dslide :host github :repo "positron-solutions/dslide")
|
||||
:commands (dslide-deck-start dslide-deck-stop)
|
||||
:custom
|
||||
(dslide-start-from 'point)
|
||||
;; Let's keep our presentations simple:
|
||||
|
@ -152,10 +302,10 @@ The [[https://github.com/positron-solutions/dslide][dslide project]] is flexible
|
|||
"<down>" '("next slide" . next-line))
|
||||
|
||||
:bind
|
||||
("C-<f5>" . dslide-deck-start)
|
||||
("C-<f5>" . ha-dslide-deck-start)
|
||||
(:map dslide-mode-map
|
||||
("<f5>" . dslide-deck-forward)
|
||||
("S-<f5>" . dslide-deck-backward)
|
||||
("<f5>" . ha-dslide-deck-forward)
|
||||
("S-<f5>" . ha-dslide-deck-backward)
|
||||
("C-<f5>" . dslide-deck-stop))
|
||||
|
||||
:hook ((dslide-start . ha-slide-setup)
|
||||
|
@ -174,16 +324,38 @@ What features do I like and want to take advantage of?
|
|||
- Hiding Blocks
|
||||
- Results Only
|
||||
|
||||
#+BEGIN_SRC emacs-lisp :tangle no
|
||||
(use-package dslide
|
||||
:config
|
||||
;; The dslide-highlight inherits from 'highlight'
|
||||
;; (set-face-attribute dslide-highlight :foreground "red")
|
||||
;; This too inherits from 'highlight'
|
||||
;; (set-face-attribute dslide-babel-success-highlight :foreground "red")
|
||||
;; This inherits from `error'
|
||||
;; (set-face-attribute dslide-babel-error-highlight :foreground "red")
|
||||
(set-face-attribute 'highlight nil :background 'unspecified :foreground "lightblue"))
|
||||
Fixes and improvements for the dslide:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun dslide (&rest ignored))
|
||||
|
||||
(defvar ha-dslide-presentation nil "The buffer name of the starting presentation.")
|
||||
|
||||
(defun ha-dslide-deck-start ()
|
||||
"Start (and remember) a dslide presentation."
|
||||
(interactive)
|
||||
(unless (eq major-mode 'org-mode)
|
||||
(call-interactively 'org-find-file))
|
||||
(setq ha-dslide-presentation (buffer-name))
|
||||
(call-interactively 'dslide-deck-start))
|
||||
|
||||
(defun ha-dslide-deck-forward ()
|
||||
"Switch to current running presentation, and advance slide deck."
|
||||
(interactive)
|
||||
(when ha-dslide-presentation
|
||||
(pop-to-buffer ha-dslide-presentation))
|
||||
(setq ha-dslide-presentation (buffer-name))
|
||||
(dslide-deck-forward))
|
||||
|
||||
(defun ha-dslide-deck-backward ()
|
||||
"Switch to current running presentation, and reverse slide deck."
|
||||
(interactive)
|
||||
(when ha-dslide-presentation
|
||||
(pop-to-buffer ha-dslide-presentation))
|
||||
(setq ha-dslide-presentation (buffer-name))
|
||||
(dslide-deck-backward))
|
||||
|
||||
(set-face-attribute 'highlight nil :background 'unspecified :foreground "lightblue")
|
||||
#+END_SRC
|
||||
|
||||
*** Master of Ceremonies
|
||||
|
@ -203,6 +375,15 @@ The =moc-screenshot= seems to only work on Linux.
|
|||
|
||||
An interesting approach for making presentations, that I’m not sure I will need.
|
||||
|
||||
*** TopSpace
|
||||
|
||||
The [[https://github.com/trevorpogue/topspace][topspace]] project can pad the top of a buffer, to make the first line in the center of the window. Helpful for presentations:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(use-package topspace
|
||||
:straight (:type git :host github :repo "trevorpogue/topspace"))
|
||||
#+END_SRC
|
||||
|
||||
*** Showing Something associated with a Headline
|
||||
:PROPERTIES:
|
||||
:DSLIDE_ACTIONS: dslide-action-babel
|
||||
|
@ -214,13 +395,13 @@ But how would I get it to close? Maybe we use a combination of actions and my
|
|||
|
||||
*Note:* Code blocks with =exports= set to =none= are not displayed.
|
||||
|
||||
#+begin_src elisp :tangle no :exports none :results none
|
||||
#+begin_src elisp :tangle no :exports none :results none :eval no
|
||||
(ha-demo-show-file "ha-org.org" :position 'right
|
||||
:focus 'presentation :heading "Meetings"
|
||||
:shift 0)
|
||||
#+end_src
|
||||
|
||||
#+BEGIN_SRC emacs-lisp :tangle no :exports none :results none
|
||||
#+BEGIN_SRC emacs-lisp :tangle no :exports none :results none :eval no
|
||||
(ha-demo-highlight-buffer :buffer "ha-org.org"
|
||||
:hi-lines "268-274")
|
||||
#+END_SRC
|
||||
|
@ -234,213 +415,59 @@ I would like to highlight a bullet point or a paragraph while talking.
|
|||
To do this, add =:DSLIDE_ACTIONS: dslide-action-highlight-paragraphs= to the properties of a section.
|
||||
|
||||
#+begin_src elisp emacs-lisp
|
||||
(defclass dslide-action-highlight-paragraphs (dslide-action)
|
||||
((overlays :initform nil))
|
||||
"Paint the paragraphs with the highlight color, one by one.")
|
||||
(use-package dslide
|
||||
:straight (:host github :repo "positron-solutions/dslide")
|
||||
:config
|
||||
(defclass dslide-action-highlight-paragraphs (dslide-action)
|
||||
((overlays :initform nil))
|
||||
"Paint the paragraphs with the highlight color, one by one.")
|
||||
|
||||
;; Default no-op `dslide-begin' is sufficient
|
||||
;; In this case, the Default no-op `dslide-begin' works.
|
||||
;; Default implementation of `dslide-end', plays forward to the end.
|
||||
|
||||
;; Default implementation of `dslide-end', which just plays forward to the end,
|
||||
;; is well-behaved with this class.
|
||||
;; Remove any remaining overlays when calling final.
|
||||
(cl-defmethod dslide-final :after ((obj dslide-action-highlight-paragraphs))
|
||||
(mapc #'delete-overlay (oref obj overlays)))
|
||||
|
||||
;; Remove any remaining overlays when calling final.
|
||||
(cl-defmethod dslide-final :after ((obj dslide-action-highlight-paragraphs))
|
||||
(mapc #'delete-overlay (oref obj overlays)))
|
||||
;; Find the next paragraph and add an overlay if it exists
|
||||
(cl-defmethod dslide-forward ((obj dslide-action-highlight-paragraphs))
|
||||
;; This line removes all overlays allowing us to highlight a new one.
|
||||
;; Remove this if you want the paragraphs to _linger_.
|
||||
(mapc #'delete-overlay (oref obj overlays))
|
||||
(when-let ((paragraph (dslide-section-next obj 'paragraph)))
|
||||
(let* ((beg (org-element-property :begin paragraph))
|
||||
(end (org-element-property :end paragraph))
|
||||
(new-overlay (make-overlay beg end)))
|
||||
(overlay-put new-overlay 'face 'highlight)
|
||||
(push new-overlay (oref obj overlays))
|
||||
;; Return non-nil indicates we made progress. This also informs the
|
||||
;; highlight when following the slides in the base buffer.
|
||||
beg)))
|
||||
|
||||
;; Find the next paragraph and add an overlay if it exists
|
||||
(cl-defmethod dslide-forward ((obj dslide-action-highlight-paragraphs))
|
||||
;; This line removes all overlays allowing us to highlight a new one.
|
||||
;; Remove this if you want the paragraphs to _linger_.
|
||||
(mapc #'delete-overlay (oref obj overlays))
|
||||
(when-let ((paragraph (dslide-section-next obj 'paragraph)))
|
||||
(let* ((beg (org-element-property :begin paragraph))
|
||||
(end (org-element-property :end paragraph))
|
||||
(new-overlay (make-overlay beg end)))
|
||||
(overlay-put new-overlay 'face 'highlight)
|
||||
(push new-overlay (oref obj overlays))
|
||||
;; Return non-nil to indicate progress was made. This also informs the
|
||||
;; highlight when following the slides in the base buffer.
|
||||
beg)))
|
||||
|
||||
(cl-defmethod dslide-backward ((obj dslide-action-highlight-paragraphs))
|
||||
(when-let* ((overlay (pop (oref obj overlays))))
|
||||
(delete-overlay overlay)
|
||||
;; If there is a preceding overlay, move to its beginning else move to the
|
||||
;; beginning of the heading.
|
||||
(if-let ((overlay (car (oref obj overlays))))
|
||||
(dslide-marker obj (overlay-start overlay))
|
||||
(dslide-marker obj (org-element-property :begin (dslide-heading obj))))))
|
||||
(cl-defmethod dslide-backward ((obj dslide-action-highlight-paragraphs))
|
||||
(when-let* ((overlay (pop (oref obj overlays))))
|
||||
(delete-overlay overlay)
|
||||
;; If there is a preceding overlay, move to its beginning else move to the
|
||||
;; beginning of the heading.
|
||||
(if-let ((overlay (car (oref obj overlays))))
|
||||
(dslide-marker obj (overlay-start overlay))
|
||||
(dslide-marker obj (org-element-property :begin (dslide-heading obj)))))))
|
||||
#+end_src
|
||||
*** Custom Action Demo
|
||||
:PROPERTIES:
|
||||
:DSLIDE_ACTIONS: dslide-action-highlight-paragraphs
|
||||
:END:
|
||||
Massachusetts, in particular, has always been one of the laboratories of democracy. It's where people try things before they're popular. It's where we experiment.
|
||||
Phasellus at dui in ligula mollis ultricies. Phasellus lacus. Fusce commodo. Nulla posuere. Nunc rutrum turpis sed pede. Pellentesque tristique imperdiet tortor. Nullam libero mauris, consequat quis, varius et, dictum id, arcu. Phasellus lacus. Sed diam. Nullam tristique diam non turpis.
|
||||
|
||||
- Red
|
||||
- Orange
|
||||
- Yellow
|
||||
|
||||
Democracy depends on an informed citizenry and the social cohesion that those citizens can show even when they disagree.
|
||||
|
||||
The essence of democracy is the resolve of individuals working together to shape our institutions and our society in ways that allow all of us to flourish.
|
||||
** My Slides
|
||||
A /full/ presentation requires my /notes/ on one frame, and the presentation on the other.
|
||||
|
||||
To use this, following:
|
||||
1. Select the Org mode presentation
|
||||
2. Run the function, =ha-slide-make-notes-frame=
|
||||
3. Reference the notes file that would be associated with the presentation
|
||||
|
||||
The end result is two frames, where updating the presentation, updates the location of the other frame to match the same headline.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(defvar ha-slide-notes-frame-name "Demonstration Notes"
|
||||
"The name of the frame that displays the presentation notes.")
|
||||
|
||||
(defvar ha-slide-notes-frame nil
|
||||
"Frame containing the presentation notes.")
|
||||
|
||||
(defvar ha-slide-notes-window nil
|
||||
"Window containing the presentation notes.")
|
||||
|
||||
(defun ha-slide-make-notes-frame (filename &optional heading)
|
||||
"Display the notes, FILENAME, in a new frame.
|
||||
If HEADING is given, jump to that `org-mode' headline."
|
||||
(interactive "fNotes File: ")
|
||||
(let ((f (selected-frame)))
|
||||
(setq ha-slide-notes-frame
|
||||
(make-frame `((name . ,ha-slide-notes-frame-name))))
|
||||
(set-frame-position ha-slide-notes-frame 1310 0)
|
||||
(set-frame-size ha-slide-notes-frame 920 1420 t)
|
||||
|
||||
;; While I could call `find-file-other-frame', I want to make
|
||||
;; sure I get the file loaded in the correct frame:
|
||||
(x-focus-frame ha-slide-notes-frame)
|
||||
(find-file filename)
|
||||
(goto-char (point-min))
|
||||
(when heading
|
||||
(re-search-forward (rx bol (one-or-more "*") (one-or-more space) (literal heading)))
|
||||
(recenter-top-bottom 0))
|
||||
|
||||
(setq ha-slide-notes-window (selected-window))
|
||||
(delete-other-windows)
|
||||
|
||||
;; Highlight the original window containing the presentation:
|
||||
(x-focus-frame f)))
|
||||
#+end_src
|
||||
|
||||
These interactive functions scroll the “notes” in the other window in another frame:
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(defun ha-slide-notes-scroll-up ()
|
||||
"Scroll the frame/window containing the notes, up."
|
||||
(interactive)
|
||||
(when ha-slide-notes-window
|
||||
(with-selected-window ha-slide-notes-window
|
||||
(scroll-up -10))))
|
||||
|
||||
(defun ha-slide-notes-scroll-down ()
|
||||
"Scroll the frame/window containing the notes, down."
|
||||
(interactive)
|
||||
(when ha-slide-notes-window
|
||||
(with-selected-window ha-slide-notes-window
|
||||
(scroll-up 10))))
|
||||
|
||||
(defun ha-slide-notes-update ()
|
||||
"Function to move the notes headline to current buffers.
|
||||
Assuming the buffer is showing an org-file, and previously
|
||||
called `ha-slide-make-notes-frame', this function moves
|
||||
the point in that buffer to the same headline."
|
||||
(interactive)
|
||||
(when ha-slide-notes-window
|
||||
(let ((heading (thread-first
|
||||
(org-get-heading t t t t)
|
||||
(substring-no-properties))))
|
||||
(with-selected-window ha-slide-notes-window
|
||||
(goto-char (point-min))
|
||||
(re-search-forward (rx (literal heading)) nil t)
|
||||
(recenter-top-bottom 0)))))
|
||||
#+end_src
|
||||
|
||||
Call the =ha-slide-notes-update= function automatically after updating a slide. With =dslide=, we add a hook:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(use-package dslide
|
||||
:hook (dslide-narrow . 'ha-slide-notes-update))
|
||||
#+END_SRC
|
||||
|
||||
|
||||
|
||||
|
||||
#+END_SRC
|
||||
|
||||
** My Presentation View
|
||||
Regardless of the presentation package I use, I make them all look similar with the following code. Much of this is getting rid of Emacs visual elements, like the cursor and the mode-line, as well as stopping minor modes that add visual changes, like spellchecking and the gutter. I can call this function from any presentation software used.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun ha-slide-setup (&optional frame-name)
|
||||
"Configure the look I want for presentations.
|
||||
The frame associated with FRAME-NAME is tidied
|
||||
by removing the gutters and other informative
|
||||
widgets not needed for a presentation."
|
||||
(org-indent-mode -1)
|
||||
;; (org-modern-mode -1)
|
||||
|
||||
(setq org-image-actual-width nil)
|
||||
(org-display-inline-images)
|
||||
(ha-org-blocks-hide-headers)
|
||||
(ha-org-hide-stars)
|
||||
(font-lock-update)
|
||||
(ha-demo-hide-mode-line)
|
||||
(ha-demo-hide-cursor)
|
||||
(ha-demo-presentation-frame frame-name)
|
||||
|
||||
(text-scale-set 4)
|
||||
(git-gutter-mode -1)
|
||||
(flycheck-mode -1)
|
||||
(jinx-mode -1)
|
||||
|
||||
;; Clear the demonstration state cache:
|
||||
(clrhash ha-demo-prev-state)
|
||||
|
||||
(evil-normal-state))
|
||||
#+END_SRC
|
||||
|
||||
And after a presentation finishes, this function cleans up by restoring minor modes, etc:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun ha-slide-teardown ()
|
||||
"Reset the Org after a presentation."
|
||||
(org-indent-mode 1)
|
||||
;; (org-modern-mode 1)
|
||||
|
||||
(ha-org-blocks-show-headers)
|
||||
(font-lock-update)
|
||||
(ha-demo-show-mode-line)
|
||||
(ha-demo-show-cursor)
|
||||
(ha-demo-normalize-frame)
|
||||
|
||||
(text-scale-set 0)
|
||||
(git-gutter-mode)
|
||||
(flycheck-mode)
|
||||
(jinx-mode))
|
||||
#+END_SRC
|
||||
|
||||
The =dslide= seems to reset /everything/ on each slide display, so:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun ha-slide-reset ()
|
||||
"Reset the current slide."
|
||||
(interactive)
|
||||
(ha-org-blocks-hide-headers)
|
||||
(font-lock-update))
|
||||
#+END_SRC
|
||||
* Donec vitae dolor.
|
||||
* Fusce commodo.
|
||||
* Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.
|
||||
|
||||
Nunc porta vulputate tellus. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec posuere augue in quam. Sed id ligula quis est convallis tempor. Integer placerat tristique nisl. Nunc rutrum turpis sed pede. Nullam rutrum. Sed id ligula quis est convallis tempor.
|
||||
* New Demonstration
|
||||
Instead of executing a sequence of demonstration steps, demonstrations key on “state”, that is, the active buffer or major-mode, or the heading of an Org file, etc. I described the [[https://howardism.org/Technical/Emacs/demonstrations-part-two.html][guts of writing this code]], but we bind a key to calling =ha-demo-step= with a list of /state matchers/ to functions to call when matched. For instance:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp :tangle no
|
||||
#+BEGIN_SRC emacs-lisp :tangle no :eval no
|
||||
(define-ha-demo ha-simple-demo
|
||||
(:heading "New Demonstration" :i 0) (message "Howdy")
|
||||
(:heading "New Demonstration" :i 1) (message "Hi there"))
|
||||
|
@ -718,6 +745,47 @@ Like the work I’m doing to the mode-line, can we make the frame cleaner for a
|
|||
(set-frame-parameter (selected-frame) 'right-fringe (nth 1 ha-demo-frame-state)))
|
||||
#+END_SRC
|
||||
|
||||
** Side Window Helpers
|
||||
The following sections create side windows (potentially) and run stuff inside them.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(cl-defun ha-demo-create-side-window (&key position keep-windows)
|
||||
"Display a side window.
|
||||
POSITION can be 'full 'right or 'below and positions the window.
|
||||
Deletes other windows unless KEEP-WINDOWS is non-nil."
|
||||
(unless position
|
||||
(setq position :right))
|
||||
|
||||
;; Remove any other windows that may be shown:
|
||||
(unless keep-windows
|
||||
(ignore-errors
|
||||
(delete-other-windows)))
|
||||
|
||||
(pcase position
|
||||
('above (progn (split-window-vertically)))
|
||||
('up (progn (split-window-vertically)))
|
||||
('left (progn (split-window-horizontally)))
|
||||
('right (progn (split-window-horizontally) (other-window 1)))
|
||||
('above (progn (split-window-vertically) (other-window 1)))
|
||||
('below (progn (split-window-vertically) (other-window 1)))))
|
||||
|
||||
(cl-defun ha-demo-set-side-window (&key size modeline cursor)
|
||||
"Standard settings for demonstration windows.
|
||||
SIZE is an integer for the font size based on the default size.
|
||||
Show MODELINE if non-nil, default is to hide it.
|
||||
The CURSOR can be 'show / 'yes or 'hide / 'no."
|
||||
(when size
|
||||
(text-scale-set size))
|
||||
|
||||
(unless modeline
|
||||
(setq-local mode-line-format nil))
|
||||
|
||||
(when cursor
|
||||
(if (or (eq cursor 'yes) (eq cursor 'show))
|
||||
(ha-demo-show-cursor)
|
||||
(ha-demo-hide-cursor))))
|
||||
#+END_SRC
|
||||
|
||||
** Display File
|
||||
Displaying a File with:
|
||||
- On the side or covering the entire frame
|
||||
|
@ -731,7 +799,8 @@ All options? Should I use Common Lisp’s =cl-defun= for the keyword parameters?
|
|||
#+BEGIN_SRC emacs-lisp
|
||||
(cl-defun ha-demo-show-file (filename &key position size modeline
|
||||
line heading shift cursor
|
||||
commands focus)
|
||||
hi-lines hi-face
|
||||
commands keep-windows focus)
|
||||
"Show a file, FILENAME, in a buffer based on keyed parameters.
|
||||
POSITION can be 'full 'right or 'below and positions the window.
|
||||
SIZE is an integer for the font size based on the default size.
|
||||
|
@ -747,38 +816,21 @@ All options? Should I use Common Lisp’s =cl-defun= for the keyword parameters?
|
|||
COMMANDS is a lambda expression that can contain any other
|
||||
instructions to happen to the buffer display."
|
||||
(let ((orig-buf (current-buffer)))
|
||||
(unless position
|
||||
(setq position :right))
|
||||
(ha-demo-create-side-window :position position :keep-windows keep-windows)
|
||||
|
||||
;; Step 1: Create a window
|
||||
(pcase position
|
||||
('above (progn (split-window-vertically)))
|
||||
('up (progn (split-window-vertically)))
|
||||
('left (progn (split-window-horizontally)))
|
||||
('right (progn (split-window-horizontally) (other-window 1)))
|
||||
('above (progn (split-window-vertically) (other-window 1)))
|
||||
('below (progn (split-window-vertically) (other-window 1))))
|
||||
|
||||
;; Step 2: Load the file or switch to the buffer:
|
||||
(if (file-exists-p filename)
|
||||
(find-file filename)
|
||||
(switch-to-buffer filename))
|
||||
|
||||
(goto-char (point-min))
|
||||
|
||||
(when cursor
|
||||
(if (or (eq cursor 'yes) (eq cursor 'show))
|
||||
(ha-demo-show-cursor)
|
||||
(ha-demo-hide-cursor)))
|
||||
|
||||
;; Step 3: Increase the font size
|
||||
(when size
|
||||
(text-scale-set size))
|
||||
|
||||
(unless modeline
|
||||
(setq-local mode-line-format nil))
|
||||
(ha-demo-set-side-window :size size :modeline modeline
|
||||
:cursor cursor)
|
||||
(when (fboundp 'topspace-mode)
|
||||
(topspace-mode 1))
|
||||
|
||||
(ha-demo-highlight-buffer :line line :heading heading :shift shift
|
||||
:hi-lines hi-lines :hi-face hi-face
|
||||
:commands commands)
|
||||
|
||||
(when (and focus (eq focus 'presentation))
|
||||
|
@ -787,13 +839,13 @@ All options? Should I use Common Lisp’s =cl-defun= for the keyword parameters?
|
|||
|
||||
Let try it all together:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp :tangle no
|
||||
#+BEGIN_SRC emacs-lisp :tangle no :eval no
|
||||
(ha-demo-show-file "ha-config.org" :position 'right :size 1 :modeline nil :line 418 :shift 4)
|
||||
#+END_SRC
|
||||
|
||||
Or:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp :tangle no
|
||||
#+BEGIN_SRC emacs-lisp :tangle no :eval no
|
||||
(ha-demo-show-file "ha-config.org" :modeline t
|
||||
:heading "Text Expanders"
|
||||
:commands (lambda () (jinx-mode -1)))
|
||||
|
@ -820,45 +872,50 @@ Perhaps when we call =ha-demo-show-file=, we want to highlight different parts o
|
|||
If HI-LINES is given, create an overlay for those lines
|
||||
based on the face, HI-FACE (if that isn't given, bold those lines).
|
||||
Finally execute COMMANDS, if given."
|
||||
(when buffer
|
||||
(pop-to-buffer buffer))
|
||||
(let ((orig-buf (current-buffer)))
|
||||
|
||||
(when line
|
||||
(if (integerp line)
|
||||
(forward-line line)
|
||||
(re-search-forward line nil t)))
|
||||
(when buffer
|
||||
(pop-to-buffer buffer))
|
||||
|
||||
(when heading
|
||||
(re-search-forward (rx bol (one-or-more "*") (one-or-more space)
|
||||
(literal heading))
|
||||
nil t))
|
||||
(when line
|
||||
(if (integerp line)
|
||||
(forward-line line)
|
||||
(re-search-forward line nil t)))
|
||||
|
||||
;; If SHIFT is positive integer, left that many line above point,
|
||||
;; otherwise don't do anything to leave it in the middle.
|
||||
;; If SHIFT is null, move it to the top of the buffer window:
|
||||
(when shift
|
||||
(if (integerp shift)
|
||||
(recenter-top-bottom shift))
|
||||
(recenter-top-bottom 0))
|
||||
(when heading
|
||||
(re-search-forward (rx bol (one-or-more "*") (one-or-more space)
|
||||
(literal heading))
|
||||
nil t))
|
||||
|
||||
;; If SHIFT is positive integer, left that many line above point,
|
||||
;; otherwise don't do anything to leave it in the middle.
|
||||
;; If SHIFT is null, move it to the top of the buffer window:
|
||||
(when shift
|
||||
(if (integerp shift)
|
||||
(recenter-top-bottom shift))
|
||||
(recenter-top-bottom 0))
|
||||
|
||||
(when hi-lines
|
||||
(remove-overlays)
|
||||
(seq-let (first-line last-line) (string-split hi-lines (rx (or ":" "-")))
|
||||
(save-excursion
|
||||
(let* ((beg (goto-line (string-to-number first-line)))
|
||||
(end (progn
|
||||
(goto-line (string-to-number last-line))
|
||||
(line-end-position)))
|
||||
(new-overlay (make-overlay beg end)))
|
||||
(when hi-lines
|
||||
(seq-let (first-line last-line) (string-split hi-lines (rx (or ":" "-")))
|
||||
(save-excursion
|
||||
(let* ((beg (goto-line (string-to-number first-line)))
|
||||
(end (progn
|
||||
(goto-line (string-to-number last-line))
|
||||
(line-end-position)))
|
||||
(new-overlay (make-overlay beg end)))
|
||||
|
||||
(if hi-face
|
||||
(overlay-put new-overlay 'face hi-face)
|
||||
(overlay-put new-overlay 'face ha-demo-highlight-2))
|
||||
(if hi-face
|
||||
(overlay-put new-overlay 'face hi-face)
|
||||
(overlay-put new-overlay 'face 'ha-demo-highlight-3))
|
||||
|
||||
;; (push new-overlay (oref obj overlays))
|
||||
))))
|
||||
;; (push new-overlay (oref obj overlays))
|
||||
))))
|
||||
|
||||
(when commands (funcall commands)))
|
||||
(when commands (funcall commands))
|
||||
|
||||
(when buffer
|
||||
(pop-to-buffer orig-buf))))
|
||||
#+END_SRC
|
||||
|
||||
Example:
|
||||
|
@ -868,6 +925,80 @@ Example:
|
|||
#+END_SRC
|
||||
|
||||
|
||||
** Shell Commands
|
||||
|
||||
Demo-like wrapper around the [[file:~/other/hamacs/ha-remoting.org::*Programmatic Interface][ha-shell]] commands, where I can make bigger shell terminals.
|
||||
|
||||
We would normally just have a single shell for a demonstration, with a name associated with the directory:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defvar ha-demo-shell-dir (getenv "HOME")
|
||||
"Store the directory for repeated commands")
|
||||
#+END_SRC
|
||||
|
||||
And we can open the shell in a window:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(cl-defun ha-demo-shell (&key directory position size modeline
|
||||
cursor command focus)
|
||||
"Open a shell, and potentially send COMMAND to it.
|
||||
POSITION can be 'full 'right or 'below and positions the window.
|
||||
SIZE is an integer for the font size based on the default size.
|
||||
Show MODELINE when non-nil, default is to hide it.
|
||||
The CURSOR can be 'show / 'yes or 'hide / 'no.
|
||||
The FOCUS can be 'presentation to return the cursor to the
|
||||
calling buffer."
|
||||
(let ((orig-buf (current-buffer)))
|
||||
(ha-demo-create-side-window :position position)
|
||||
|
||||
(when directory
|
||||
(setq ha-demo-shell-dir directory))
|
||||
|
||||
;; We could also do ha-ssh
|
||||
(ha-shell ha-demo-shell-dir)
|
||||
|
||||
(ha-demo-set-side-window :size size :modeline modeline :cursor cursor)
|
||||
|
||||
(when command
|
||||
(sit-for 1)
|
||||
(ha-shell-send command ha-demo-shell-dir))
|
||||
|
||||
(when (and focus (eq focus 'presentation))
|
||||
(pop-to-buffer orig-buf))))
|
||||
|
||||
(defun ha-demo-shell-send (command)
|
||||
"Send COMMAND to the currently opened shell, `ha-demo-shell'."
|
||||
(ha-shell-send command ha-demo-shell-dir))
|
||||
|
||||
(defun ha-demo-shell-quit ()
|
||||
"Close the window associated with a shell."
|
||||
(ha-shell-send "exit" ha-demo-shell-dir)
|
||||
(delete-other-windows))
|
||||
#+END_SRC
|
||||
|
||||
Try it out:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp :tangle no
|
||||
(ha-demo-shell :position 'right :directory "/tmp" :command "ls -l")
|
||||
#+END_SRC
|
||||
|
||||
And:
|
||||
#+BEGIN_SRC emacs-lisp :tangle no
|
||||
(ha-demo-shell-send "date > now.txt")
|
||||
|
||||
(ha-demo-shell-send "cat now.txt")
|
||||
#+END_SRC
|
||||
|
||||
** Delete Specific Windows
|
||||
While often safe to call =delete-other-windows=, being able to delete a particular window that hosts a particular buffer seems helpful.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun ha-demo-delete-window (bufname)
|
||||
"Delete the window associated with BUFNAME."
|
||||
(ignore-errors
|
||||
(delete-window (get-buffer-window bufname))))
|
||||
#+END_SRC
|
||||
|
||||
* Technical Artifacts :noexport:
|
||||
Let's =provide= a name so we can =require= this file:
|
||||
|
||||
|
@ -885,3 +1016,7 @@ Let's =provide= a name so we can =require= this file:
|
|||
#+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:
|
||||
# jinx-local-words: "Modeline"
|
||||
# End:
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#+title: Emacs Graphical Display Configuration
|
||||
#+author: Howard X. Abrams
|
||||
#+date: 2020-09-10
|
||||
#+tags: emacs macos
|
||||
#+TITLE: Emacs Graphical Display Configuration
|
||||
#+AUTHOR: Howard X. Abrams
|
||||
#+DATE: 2020-09-10
|
||||
#+TAGS: emacs macos
|
||||
|
||||
A literate programming file to configure the Emacs UI.
|
||||
|
||||
|
@ -407,12 +407,6 @@ And of course, the default is /inside/ where my mind is dark and safe:
|
|||
|
||||
#+begin_src emacs-lisp
|
||||
(add-to-list 'custom-theme-load-path hamacs-source-dir)
|
||||
|
||||
;; (ha-hamacs-load "ha-theme.org")
|
||||
;; (ha-hamacs-tangle "ha-theme.org")
|
||||
(require 'hamacs-theme)
|
||||
(load-theme 'hamacs)
|
||||
|
||||
(laptop-inside)
|
||||
#+end_src
|
||||
** Highlight Task Labels
|
||||
|
|
|
@ -877,11 +877,6 @@ Since I tweaked the help menu, I craft my own menu:
|
|||
"h C-g" '(keyboard-escape-quit :which-key t))
|
||||
#+end_src
|
||||
|
||||
Some of these call the [[file:ha-programming-elisp.org::*Helpful Functions][Helpful]] package:
|
||||
#+begin_src emacs-lisp
|
||||
(use-package helpful)
|
||||
#+end_src
|
||||
|
||||
Remember these keys in the *Help* buffer:
|
||||
- ~s~ :: view source of the function
|
||||
- ~i~ :: view info manual of the function
|
||||
|
|
|
@ -8,7 +8,7 @@ A literate program for configuring org files for work-related notes.
|
|||
#+begin_src emacs-lisp :exports none
|
||||
;;; org-sprint --- Configuring org files for work-related notes. -*- lexical-binding: t; -*-
|
||||
;;
|
||||
;; © 2020-2024 Howard X. Abrams
|
||||
;; © 2020-2025 Howard X. Abrams
|
||||
;; Licensed under a Creative Commons Attribution 4.0 International License.
|
||||
;; See http://creativecommons.org/licenses/by/4.0/
|
||||
;;
|
||||
|
@ -43,10 +43,40 @@ I give each sprint a nickname, based on a /theme/ of some sorts, alphabetized. S
|
|||
|
||||
At the beginning of the year, I choose a theme, and make a list for the upcoming sprints. In the org file, this is a list, that gets /tangled/ into an actual Emacs LIsp list. This is pretty cool.
|
||||
|
||||
#+begin_src emacs-lisp :var sprint-names=sprint-names-2024
|
||||
#+begin_src emacs-lisp :var sprint-names=sprint-names-2025
|
||||
(defvar sprint-nicknames sprint-names
|
||||
"List of 26 Sprint Nicknames from A to Z.")
|
||||
#+end_src
|
||||
** 2025
|
||||
This year is the animals representing corporate slogans:
|
||||
|
||||
#+name: sprint-names-2025
|
||||
- Accelerated and Adaptive Ant
|
||||
- Buy-in Bee and Blue-sky Bull
|
||||
- Circle-Back Contingency Cat
|
||||
- Dirty Deploying Dog
|
||||
- End Game Echidna (E-tail)
|
||||
- Future Forward Fox
|
||||
- Growth Hack Hippo
|
||||
- Honest Abe Conversation
|
||||
- Interactive Ibex
|
||||
- Catalyst for Change Jaguar
|
||||
- Knowledge-based Kid
|
||||
- Lettuce Align on Logistical Innovating Leopard
|
||||
- Market Moving Moose
|
||||
- Software as a Service Snipe
|
||||
- Outside-the-Box Ostrich
|
||||
- Pivot Point Penguin and Paradigm Shift Porpoise
|
||||
- Quality Controlling Quakka
|
||||
- Revenue Ride Rhino
|
||||
- Synergy Snake
|
||||
- Transformational Tiger
|
||||
- Uber-Efficient Urchin
|
||||
- Vertical Value Add Vole
|
||||
- Web-based Initiative Whale (Win-Win)
|
||||
- Challenging Left-Field Assumptions
|
||||
– Bitcoin, Bitcoin, Bitcoin
|
||||
- Low-Hanging Fruitbat
|
||||
** 2024
|
||||
How about Tabaxi names this year … especially since my next character has to be a cat man.
|
||||
#+name: sprint-names-2024
|
||||
|
@ -250,6 +280,14 @@ Emacs have an internal rep of a time.
|
|||
|
||||
** Sprint Numbering
|
||||
|
||||
Each year, specify the first day of the first sprint of the year:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defvar sprint-start-date (get-date-time "2025-01-14")
|
||||
"The date of the first day of the first sprint of the year.
|
||||
See `sprint-range'.")
|
||||
#+END_SRC
|
||||
|
||||
My Sprint starts on Tuesday, 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.")
|
||||
|
@ -258,7 +296,7 @@ My Sprint starts on Tuesday, but this sometimes changed, so let's make this a va
|
|||
We seem to never start our Sprints correctly, and we seem to like offsets:
|
||||
#+begin_src emacs-lisp
|
||||
;; CHANGEME Each year as this never matches:
|
||||
(defvar sprint-offset-value 11 "The number of the first sprint.")
|
||||
(defvar sprint-offset-value 0 "The number of the first sprint.")
|
||||
#+end_src
|
||||
|
||||
We label our sprint based on the week number that it starts. Note that on a Monday, I want to consider that we are still numbering from last week.
|
||||
|
@ -279,6 +317,9 @@ We label our sprint based on the week number that it starts. Note that on a Mond
|
|||
Let's have these tests to make of this /weekly/ perspective:
|
||||
#+begin_src emacs-lisp :tangle no
|
||||
(ert-deftest sprint-week-num-test ()
|
||||
(should (= (sprint-week-num "2025-01-13") 2)) ; Monday previous week
|
||||
(should (= (sprint-week-num "2025-01-14") 3)) ; Monday previous week
|
||||
|
||||
(should (= (sprint-week-num "2024-01-01") 0)) ; Monday previous week
|
||||
(should (= (sprint-week-num "2024-01-02") 1)) ; Tuesday ... this week
|
||||
(should (= (sprint-week-num "2024-01-09") 2)) ; Monday, next week, part of last
|
||||
|
@ -294,27 +335,23 @@ This year, my PM decided to start the sprints sequentially starting with 11, so
|
|||
"Return the current sprint number, with some assumptions that
|
||||
each sprint is two weeks long, starting on Tuesday."
|
||||
(let* ((num (sprint-week-num date))
|
||||
;; Depending on how late we wait to start the sprint, the
|
||||
;; new sprint may be on an oddp or evenp week:
|
||||
(bucket (if (cl-oddp num) num (1- num))))
|
||||
(thread-first bucket
|
||||
;; Make 2 week sprints sequential:
|
||||
(/ 2)
|
||||
;; Sprint offset number:
|
||||
;; (+ sprint-offset-value)
|
||||
1+
|
||||
)))
|
||||
(- sprint-offset-value))))
|
||||
#+end_src
|
||||
|
||||
And some tests to verify that:
|
||||
#+begin_src emacs-lisp :tangle no
|
||||
(ert-deftest sprint-number-test ()
|
||||
(should (= (sprint-number "2024-01-02") 1))
|
||||
(should (= (sprint-number "2024-01-10") 1))
|
||||
(should (= (sprint-number "2024-01-15") 1))
|
||||
(should (= (sprint-number "2024-01-16") 2))
|
||||
(should (= (sprint-number "2024-01-23") 2))
|
||||
(should (= (sprint-number "2024-01-29") 2))
|
||||
(should (= (sprint-number "2024-01-30") 3))
|
||||
(should (= (sprint-number "2024-02-13") 4)))
|
||||
(should (= (sprint-number "2025-01-13") 0))
|
||||
(should (= (sprint-number "2025-01-14") 1))
|
||||
(should (= (sprint-number "2025-01-21") 1))
|
||||
(should (= (sprint-number "2025-01-28") 2)))
|
||||
#+end_src
|
||||
** Sprint File Name
|
||||
I create my org-file notes based on the Sprint number.
|
||||
|
@ -377,7 +414,6 @@ These test won't pass any more, as the nickname of the sprint changes from year
|
|||
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 Tuesday/ of the year, so I need to begin the year changing this value. I should fix this.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
;; (setq number-or-date "2024-01-16")
|
||||
(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.
|
||||
|
@ -386,10 +422,7 @@ I want to print the beginning and ending of the sprint, where we have a sprint n
|
|||
(let* ((num (if (or (null number-or-date) (stringp number-or-date))
|
||||
(* 2 (1- (sprint-number number-or-date)))
|
||||
(1- number-or-date)))
|
||||
;; CHANGEME each year to mark the first day of the first sprint:
|
||||
(time-start (-> "2024-01-02" ; Converted to time
|
||||
get-date-time
|
||||
float-time))
|
||||
(time-start (float-time sprint-start-date))
|
||||
(day-length (* 3600 24)) ; Length of day in seconds
|
||||
(week-length (* day-length 7))
|
||||
(sprint-start (time-add time-start (* week-length num)))
|
||||
|
@ -433,7 +466,7 @@ Due to the regularity of the sprint cadence, I can pre-schedule meetings and oth
|
|||
|
||||
#+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."
|
||||
"Return formatted date string from number of DAYS from the start of the sprint."
|
||||
(let* ((day-length (* 3600 24))
|
||||
(start (car (sprint-range)))
|
||||
(adate (time-add start (* day-length days))))
|
||||
|
|
|
@ -40,17 +40,23 @@ The [[https://github.com/tarsius/paren-face][paren-face]] project lowers the col
|
|||
:hook (emacs-lisp-mode . paren-face-mode))
|
||||
#+end_src
|
||||
|
||||
** Helpful Functions
|
||||
|
||||
Show code examples with the [[https://github.com/xuchunyang/elisp-demos][elisp-demos]] package.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(use-package elisp-demos
|
||||
:config
|
||||
(advice-add 'describe-function-1 :after #'elisp-demos-advice-describe-function-1))
|
||||
#+end_src
|
||||
** Helpful Functions
|
||||
Let’s take advantage of [[https://github.com/Wilfred/helpful][helpful]] package for getting more information into the =describe-function= call.
|
||||
|
||||
Find a function without a good demonstration? Call =elisp-demos-add-demo=.
|
||||
|
||||
Let’s take advantage of [[https://github.com/Wilfred/helpful][helpful]] package for getting more information into the =describe-function= call, but note that this package doesn’t seem to be compatible with Emacs v30.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(use-package helpful)
|
||||
(use-package helpful
|
||||
:if (version< emacs-version "30"))
|
||||
#+end_src
|
||||
|
||||
And we should extend it with the [[https://github.com/xuchunyang/elisp-demos][elisp-demos]] project:
|
||||
|
@ -62,8 +68,6 @@ And we should extend it with the [[https://github.com/xuchunyang/elisp-demos][el
|
|||
(advice-add 'helpful-update :after #'elisp-demos-advice-helpful-update))
|
||||
#+end_src
|
||||
|
||||
Find a function without a good demonstration? Call =elisp-demos-add-demo=.
|
||||
|
||||
Wilfred’s [[https://github.com/Wilfred/suggest.el][suggest]] function helps you find the right function. Basically, you type in the parameters of a function, and then the desired output, and it will write the function call.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
|
|
37
ha-theme.org
37
ha-theme.org
|
@ -1,8 +1,8 @@
|
|||
#+title: Hamacs Color Theme
|
||||
#+author: Howard Abrams
|
||||
#+date: 2024-06-18
|
||||
#+filetags: emacs hamacs
|
||||
#+lastmod: [2024-12-10 Tue]
|
||||
#+TITLE: Hamacs Color Theme
|
||||
#+AUTHOR: Howard Abrams
|
||||
#+DATE: 2024-06-18
|
||||
#+FILETAGS: emacs hamacs
|
||||
#+LASTMOD: [2025-01-14 Tue]
|
||||
|
||||
A literate programming file for defining a warm, autumn, but subtle color theme for Emacs.
|
||||
|
||||
|
@ -367,7 +367,7 @@ Let’s make a /theme/:
|
|||
`(parenthesis ((t (:foreground ,gray-50))))
|
||||
`(show-paren-match ((t (:foreground ,cursor :weight ultra-bold))))
|
||||
|
||||
`(org-link ((t (:foreground ,link-color))))
|
||||
`(org-link ((t (:foreground ,link-color :inherit variable-pitch))))
|
||||
`(org-code ((t (:foreground ,almond))))
|
||||
`(org-verbatim ((t (:foreground ,gray-95))))
|
||||
|
||||
|
@ -419,6 +419,19 @@ Let’s make a /theme/:
|
|||
`(vertico-group-multiline ((t (:foreground ,gray-45))))
|
||||
`(vertico-group-title ((t (:foreground ,gray-45))))
|
||||
|
||||
`(term-color-red ((t (:foreground ,red2-lt))))
|
||||
`(term-color-green ((t (:foreground ,green-lt))))
|
||||
`(term-color-blue ((t (:foreground ,blue-lt))))
|
||||
`(term-color-magenta ((t (:foreground ,purple-lt))))
|
||||
`(term-color-yellow ((t (:foreground ,yellow-lt))))
|
||||
`(term-color-cyan ((t (:foreground ,slate))))
|
||||
`(term-color-bright-red ((t (:foreground ,red2))))
|
||||
`(term-color-bright-green ((t (:foreground ,green))))
|
||||
`(term-color-bright-blue ((t (:foreground ,blue))))
|
||||
`(term-color-bright-magenta ((t (:foreground ,purple))))
|
||||
`(term-color-bright-yellow ((t (:foreground ,yellow))))
|
||||
`(term-color-bright-cyan ((t (:foreground ,slate))))
|
||||
|
||||
`(sh-heredoc ((t (:foreground ,almond))))
|
||||
`(sh-quoted-exec ((t (:foreground ,orange2-lt))))
|
||||
|
||||
|
@ -427,7 +440,16 @@ Let’s make a /theme/:
|
|||
|
||||
`(mastodon-display-name-face ((t (:foreground ,orange-lt))))
|
||||
`(mastodon-boosted-face ((t (:foreground ,green-lt))))
|
||||
))
|
||||
|
||||
`(message-header-name ((t (:foreground ,gray-70))))
|
||||
`(message-header-to ((t (:foreground ,dk-green-lt))))
|
||||
`(message-header-cc ((t (:foreground ,dk-green))))
|
||||
`(message-header-bcc ((t (:foreground ,dk-green))))
|
||||
`(message-header-subject ((t (:foreground ,orange-lt :weight ultra-bold))))
|
||||
`(message-header-other ((t (:foreground ,red2))))
|
||||
|
||||
`(elfeed-search-feed-face ((t (:foreground ,brown-lt))))
|
||||
`(elfeed-search-tag-face ((t (:foreground ,slate))))))
|
||||
#+END_SRC
|
||||
|
||||
[[file:ha-theme-results.png]]
|
||||
|
@ -449,4 +471,3 @@ Let's =provide= a name so we can =require= this file:
|
|||
#+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
|
||||
-
|
||||
|
|
|
@ -2,6 +2,6 @@
|
|||
# name: Hugo Callout
|
||||
# key: callout
|
||||
# --
|
||||
{{< callout type="${2:$$(yas-choose-value '("note" "warning" "hint"))}" >}}
|
||||
{{< callout type="${2:$$(yas-choose-value '("note" "info" "error" "warning" "hint"))}" >}}
|
||||
$0
|
||||
{{< /callout >}}
|
||||
|
|
5
snippets/markdown-mode/figure
Normal file
5
snippets/markdown-mode/figure
Normal file
|
@ -0,0 +1,5 @@
|
|||
# -*- mode: snippet -*-
|
||||
# name: figure
|
||||
# key: figure
|
||||
# --
|
||||
{{< figure src="${1}" title="${2}" >}}
|
14
snippets/markdown-mode/front-matter
Normal file
14
snippets/markdown-mode/front-matter
Normal file
|
@ -0,0 +1,14 @@
|
|||
# -*- mode: snippet -*-
|
||||
# name: Front Matter
|
||||
# key: <front
|
||||
# --
|
||||
---
|
||||
title: ${1}
|
||||
linkTitle: ${2}
|
||||
type: docs
|
||||
weight: ${3:50}
|
||||
${4:next: ${5:`(file-name-base (read-file-name "Next: "))`}}
|
||||
${6:prev: ${7:`(file-name-base (read-file-name "Prev: "))`}}
|
||||
---
|
||||
|
||||
$0
|
9
snippets/org-mode/emacs-lisp-use-package
Normal file
9
snippets/org-mode/emacs-lisp-use-package
Normal file
|
@ -0,0 +1,9 @@
|
|||
# -*- mode: snippet -*-
|
||||
# name: emacs-lisp-use-package
|
||||
# key: <slu
|
||||
# --
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(use-package ${1:package}
|
||||
:straight (:type git ${2::host ${3:github}} :repo "${4:repo}")
|
||||
$0)
|
||||
#+END_SRC
|
Before Width: | Height: | Size: 130 KiB After Width: | Height: | Size: 130 KiB |
|
@ -1,9 +1,9 @@
|
|||
#+title: `(sprint-current-name)`
|
||||
#+author: `user-full-name`
|
||||
#+email: `user-mail-address`
|
||||
#+date: `(sprint-date-range)`
|
||||
#+category: sprint
|
||||
#+filetags: :work:
|
||||
#+TITLE: `(sprint-current-name)`
|
||||
#+AUTHOR: `user-full-name`
|
||||
#+EMAIL: `user-mail-address`
|
||||
#+DATE: `(sprint-date-range)`
|
||||
#+CATEGORY: sprint
|
||||
#+FILETAGS: :work:
|
||||
|
||||
* Work Issues
|
||||
$0
|
||||
|
@ -20,9 +20,9 @@ Anything that doesn't fit the above goes here.
|
|||
* Notes for Next Sprint
|
||||
|
||||
|
||||
#+description: Notes taken during Sprint #`(sprint-number)`
|
||||
#+property: header-args: :results drawer :tangle no :eval no-export :comments org
|
||||
#+options: num:nil toc:t todo:nil tasks:nil tags:nil skip:nil author:nil email:nil creator:nil timestamp:nil ^:nil
|
||||
#+DESCRIPTION: Notes taken during Sprint #`(sprint-number)`
|
||||
#+PROPERTY: header-args: :results drawer :tangle no :eval no-export :comments org
|
||||
#+OPTIONS: num:nil toc:t todo:nil tasks:nil tags:nil skip:nil author:nil email:nil creator:nil timestamp:nil ^:nil
|
||||
|
||||
# Local Variables:
|
||||
# eval: (org-content 2)
|
||||
|
|
Loading…
Reference in a new issue