Compare commits
2 Commits
c6da80b572
...
b437178c64
Author | SHA1 | Date |
---|---|---|
TEC | b437178c64 | |
TEC | b67cc0a39c |
|
@ -1,4 +0,0 @@
|
|||
RewriteEngine on
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule .* 404.html [L]
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -5,7 +5,7 @@
|
|||
</a>
|
||||
To the extent possible under law,
|
||||
<a rel="dct:publisher"
|
||||
href="https://blog.tecosaur.com/">
|
||||
href="https://blog.tecosaur.net/">
|
||||
<span property="dct:title">TEC</span></a>
|
||||
has waived all copyright and related or neighboring rights to
|
||||
<span property="dct:title" style="font-style:italic">This Month in Org</span>.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<header>
|
||||
<h4><a href="https://orgmode.org" class="orgicorn"><img src="org-icon-monochrome.svg" class="invertible"></a>
|
||||
<a href="https://blog.tecosaur.com/tmio/" class="title">
|
||||
<a href="https://blog.tecosaur.net/tmio/" class="title">
|
||||
This Month in Org</a>
|
||||
<a href="rss.xml" title="RSS Feed" type="application/rss+xml" class="rss">
|
||||
<img src="rss.svg" alt="RSS icon" />
|
||||
|
|
|
@ -75,45 +75,87 @@ summary {
|
|||
display: list-item; }
|
||||
|
||||
/*! end normalise.css */
|
||||
#page {
|
||||
--accent: #002642;
|
||||
--accent-dark: #00151c;
|
||||
--code-foreground: #2c3e50;
|
||||
--code-background: #efefef;
|
||||
--code-func: #6c3163;
|
||||
--code-const: #4e3163;
|
||||
--code-regex: #655370;
|
||||
--back-white: #fff;
|
||||
--back-light: #f0eeed;
|
||||
--back-medium: #c8c8c8;
|
||||
--text-light: #7b7b7b;
|
||||
--text-gray: #444;
|
||||
--text-medium: #222;
|
||||
--text-dark: #000;
|
||||
--switch-icon: "🌚";
|
||||
--switch-shadow-color: #373d4e;
|
||||
--switch-text: "dark mode?"; }
|
||||
@media (prefers-color-scheme: light) {
|
||||
#page {
|
||||
--accent: #002642;
|
||||
--accent-dark: #00151c;
|
||||
--code-foreground: #2c3e50;
|
||||
--code-background: #f5f5f5;
|
||||
--code-func: #6c3163;
|
||||
--code-const: #4e3163;
|
||||
--code-regex: #655370;
|
||||
--back-white: #fff;
|
||||
--back-light: #f0eeed;
|
||||
--back-medium: #c8c8c8;
|
||||
--text-light: #7b7b7b;
|
||||
--text-gray: #444;
|
||||
--text-medium: #222;
|
||||
--text-dark: #000;
|
||||
--switch-icon: "🌚";
|
||||
--switch-shadow-color: #373d4e;
|
||||
--switch-text: "dark mode?"; }
|
||||
#theme-switch:checked ~ #page {
|
||||
--accent: #002642;
|
||||
--accent-dark: #daf1ff;
|
||||
--code-foreground: #a1a8ae;
|
||||
--code-background: #222;
|
||||
--code-func: #bd56ad;
|
||||
--code-const: #8755ab;
|
||||
--code-regex: #a184b3;
|
||||
--back-white: #000;
|
||||
--back-light: #181818;
|
||||
--back-medium: #444;
|
||||
--text-light: #7b7b7b;
|
||||
--text-gray: #c8c8c8;
|
||||
--text-medium: #ddd;
|
||||
--text-dark: #efefef;
|
||||
--switch-icon: "🌝";
|
||||
--switch-shadow-color: #fce477;
|
||||
--switch-text: "light mode?"; }
|
||||
#theme-switch:checked ~ #page img.invertible, #theme-switch:checked ~ #page object[type="image/svg+xml"].invertible, #theme-switch:checked ~ #page img.org-latex {
|
||||
filter: invert(90.5%) hue-rotate(180deg) sepia(1%); } }
|
||||
|
||||
#theme-switch:checked ~ #page {
|
||||
--accent: #002642;
|
||||
--accent-dark: #daf1ff;
|
||||
--code-foreground: #a1a8ae;
|
||||
--code-background: #222;
|
||||
--code-func: #bd56ad;
|
||||
--code-const: #8755ab;
|
||||
--code-regex: #a184b3;
|
||||
--back-white: #000;
|
||||
--back-light: #181818;
|
||||
--back-medium: #444;
|
||||
--text-light: #7b7b7b;
|
||||
--text-gray: #c8c8c8;
|
||||
--text-medium: #ddd;
|
||||
--text-dark: #efefef;
|
||||
--switch-icon: "🌝";
|
||||
--switch-shadow-color: #fce477;
|
||||
--switch-text: "light mode?"; }
|
||||
#theme-switch:checked ~ #page img.invertible, #theme-switch:checked ~ #page object.invertible[type="image/svg+xml"] {
|
||||
filter: invert(90%) hue-rotate(180deg) sepia(1%); }
|
||||
@media (prefers-color-scheme: dark) {
|
||||
#theme-switch:checked ~ #page {
|
||||
--accent: #002642;
|
||||
--accent-dark: #00151c;
|
||||
--code-foreground: #2c3e50;
|
||||
--code-background: #f5f5f5;
|
||||
--code-func: #6c3163;
|
||||
--code-const: #4e3163;
|
||||
--code-regex: #655370;
|
||||
--back-white: #fff;
|
||||
--back-light: #f0eeed;
|
||||
--back-medium: #c8c8c8;
|
||||
--text-light: #7b7b7b;
|
||||
--text-gray: #444;
|
||||
--text-medium: #222;
|
||||
--text-dark: #000;
|
||||
--switch-icon: "🌚";
|
||||
--switch-shadow-color: #373d4e;
|
||||
--switch-text: "dark mode?"; }
|
||||
#theme-switch:checked ~ #page img.invertible, #theme-switch:checked ~ #page object[type="image/svg+xml"].invertible, #theme-switch:checked ~ #page img.org-latex {
|
||||
filter: invert(7%) sepia(4%); }
|
||||
#page {
|
||||
--accent: #002642;
|
||||
--accent-dark: #daf1ff;
|
||||
--code-foreground: #a1a8ae;
|
||||
--code-background: #222;
|
||||
--code-func: #bd56ad;
|
||||
--code-const: #8755ab;
|
||||
--code-regex: #a184b3;
|
||||
--back-white: #000;
|
||||
--back-light: #181818;
|
||||
--back-medium: #444;
|
||||
--text-light: #7b7b7b;
|
||||
--text-gray: #c8c8c8;
|
||||
--text-medium: #ddd;
|
||||
--text-dark: #efefef;
|
||||
--switch-icon: "🌝";
|
||||
--switch-shadow-color: #fce477;
|
||||
--switch-text: "light mode?"; }
|
||||
#page img.invertible, #page object[type="image/svg+xml"].invertible, #page img.org-latex {
|
||||
filter: invert(90.5%) hue-rotate(180deg) sepia(1%); } }
|
||||
|
||||
#theme-switch {
|
||||
display: none; }
|
||||
|
@ -356,23 +398,22 @@ aside {
|
|||
border-radius: 5px;
|
||||
font-family: "Open Sans", sans;
|
||||
font-weight: normal;
|
||||
font-size: 15px;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
color: var(--text-gray);
|
||||
margin: 20px 0;
|
||||
padding: 5px 20px 10px;
|
||||
line-height: 1.6 !important; }
|
||||
aside p {
|
||||
font-family: "Open Sans", sans;
|
||||
font-weight: normal;
|
||||
font-size: 15px;
|
||||
line-height: 1.6;
|
||||
color: var(--text-gray);
|
||||
line-height: 1.6 !important; }
|
||||
aside pre {
|
||||
font-size: 12px;
|
||||
border: none;
|
||||
padding-left: 0; }
|
||||
aside :first-child {
|
||||
margin-top: 0.5em; }
|
||||
aside :last-child {
|
||||
margin-bottom: 0.5em; }
|
||||
|
||||
@media (min-width: 1280px) {
|
||||
aside {
|
||||
|
@ -394,7 +435,9 @@ blockquote {
|
|||
padding-left: 15px; }
|
||||
blockquote p {
|
||||
display: inline;
|
||||
font-size: 13px; }
|
||||
font-size: 14px; }
|
||||
blockquote ol, blockquote ul {
|
||||
margin-left: 1em; }
|
||||
blockquote footer {
|
||||
font-family: "Open Sans", sans;
|
||||
font-weight: normal;
|
||||
|
@ -528,6 +571,37 @@ div.error::before {
|
|||
line-height: 1.1;
|
||||
text-align: center; }
|
||||
|
||||
div.notes {
|
||||
background: rgba(113, 90, 177, 0.15);
|
||||
border-left: 4px solid rgba(113, 90, 177, 0.45);
|
||||
margin: 1.8rem 0 1.25rem 15px;
|
||||
padding: 0.8em;
|
||||
line-height: 1.4;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
clear: both; }
|
||||
div.notes p {
|
||||
margin: 0; }
|
||||
|
||||
div.notes::before {
|
||||
content: "✎";
|
||||
color: var(--back-white);
|
||||
background: rgba(113, 90, 177, 0.8);
|
||||
align-items: flex-end;
|
||||
top: -1rem;
|
||||
font-weight: 700;
|
||||
font-size: 1.4rem;
|
||||
-webkit-clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%);
|
||||
clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%);
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
left: -1.2rem;
|
||||
line-height: 1.3;
|
||||
text-align: center; }
|
||||
|
||||
.org-ref-bib-h1 {
|
||||
margin-top: 70px;
|
||||
padding-top: 30px;
|
||||
|
@ -606,8 +680,8 @@ pre.src:empty {
|
|||
code {
|
||||
font-family: SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
|
||||
color: var(--code-foreground);
|
||||
font-size: 15px;
|
||||
padding: 0 5px; }
|
||||
font-size: 14px;
|
||||
padding: 0 2px; }
|
||||
|
||||
kbd {
|
||||
display: inline-block;
|
||||
|
@ -633,7 +707,7 @@ details.code {
|
|||
position: relative; }
|
||||
details.code summary {
|
||||
position: relative;
|
||||
left: -3px;
|
||||
left: -2.5px;
|
||||
padding-left: 10px;
|
||||
padding-bottom: 4px;
|
||||
margin-left: -10px;
|
||||
|
@ -1187,7 +1261,8 @@ hr {
|
|||
margin-top: 40px; }
|
||||
|
||||
a {
|
||||
color: inherit; }
|
||||
color: inherit;
|
||||
position: relative; }
|
||||
|
||||
figcaption a,
|
||||
p a,
|
||||
|
@ -1195,12 +1270,12 @@ p a,
|
|||
table a,
|
||||
li a,
|
||||
dl a {
|
||||
background-image: linear-gradient(var(--text-dark), var(--text-dark));
|
||||
background-size: 1px 1px;
|
||||
background-repeat: repeat-x;
|
||||
background-position: 0% 95%;
|
||||
border-radius: 1px;
|
||||
text-decoration: none; }
|
||||
text-decoration-line: underline;
|
||||
text-decoration-style: dotted;
|
||||
text-decoration-color: var(--text-light);
|
||||
text-decoration-thickness: .1em;
|
||||
text-underline-offset: 1.5px;
|
||||
border-radius: 1px; }
|
||||
figcaption a::selection,
|
||||
p a::selection,
|
||||
.page-tags a::selection,
|
||||
|
@ -1252,31 +1327,35 @@ dl a {
|
|||
dl a:hover {
|
||||
opacity: 0.9;
|
||||
filter: drop-shadow(1px 1px 1px var(--back-white));
|
||||
background-image: linear-gradient(var(--text-dark), var(--text-dark));
|
||||
background-size: 1px 1px;
|
||||
background-repeat: repeat-x;
|
||||
background-position: 0% 95%;
|
||||
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg id='squiggle-link' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' xmlns:ev='http://www.w3.org/2001/xml-events' viewBox='0 0 20 4'%3E%3Cstyle type='text/css'%3E.squiggle{animation:shift .3s linear infinite;}@keyframes shift {from {transform:translateX(0);}to {transform:translateX(-20px);}}%3C/style%3E%3Cpath fill='none' stroke='%23000000' stroke-width='2' class='squiggle' d='M0,3.5 c 5,0,5,-3,10,-3 s 5,3,10,3 c 5,0,5,-3,10,-3 s 5,3,10,3'/%3E%3C/svg%3E") !important;
|
||||
background-position: 0% 100%;
|
||||
background-size: 0.8em auto;
|
||||
text-decoration: none; }
|
||||
figcaption a:hover::selection,
|
||||
p a:hover::selection,
|
||||
.page-tags a:hover::selection,
|
||||
table a:hover::selection,
|
||||
li a:hover::selection,
|
||||
dl a:hover::selection {
|
||||
background: var(--back-white); }
|
||||
figcaption a:hover::before,
|
||||
p a:hover::before,
|
||||
.page-tags a:hover::before,
|
||||
table a:hover::before,
|
||||
li a:hover::before,
|
||||
dl a:hover::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
mask-image: url("data:image/svg+xml;charset=utf8,%3Csvg id='squiggle-link' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' xmlns:ev='http://www.w3.org/2001/xml-events' viewBox='0 0 20 4'%3E%3Cstyle type='text/css'%3E.squiggle{animation:shift .3s linear infinite;}@keyframes shift {from {transform:translateX(0);}to {transform:translateX(-20px);}}%3C/style%3E%3Cpath fill='none' stroke='%23000000' stroke-width='2' class='squiggle' d='M0,3.5 c 5,0,5,-3,10,-3 s 5,3,10,3 c 5,0,5,-3,10,-3 s 5,3,10,3'/%3E%3C/svg%3E") !important;
|
||||
mask-position: 0% 100%;
|
||||
mask-size: 0.8em auto;
|
||||
mask-repeat: repeat-x;
|
||||
background: var(--text-light); }
|
||||
figcaption a[href^="#"],
|
||||
p a[href^="#"],
|
||||
.page-tags a[href^="#"],
|
||||
table a[href^="#"],
|
||||
li a[href^="#"],
|
||||
dl a[href^="#"] {
|
||||
background-image: linear-gradient(var(--text-gray), var(--text-gray));
|
||||
background-size: 1px 1px;
|
||||
background-repeat: repeat-x;
|
||||
background-position: 0% 95%; }
|
||||
text-decoration-line: underline;
|
||||
text-decoration-style: dotted;
|
||||
text-decoration-color: var(--text-light);
|
||||
text-decoration-thickness: .1em;
|
||||
text-underline-offset: 1.5px; }
|
||||
figcaption a[href^="#"]::selection,
|
||||
p a[href^="#"]::selection,
|
||||
.page-tags a[href^="#"]::selection,
|
||||
|
@ -1292,10 +1371,11 @@ dl a {
|
|||
dl a[href^="#"]:hover {
|
||||
opacity: 0.9;
|
||||
filter: drop-shadow(1px 1px 1px var(--back-white));
|
||||
background-image: linear-gradient(var(--text-medium), var(--text-medium));
|
||||
background-size: 1px 1px;
|
||||
background-repeat: repeat-x;
|
||||
background-position: 0% 95%; }
|
||||
text-decoration-line: underline;
|
||||
text-decoration-style: dotted;
|
||||
text-decoration-color: var(--text-light);
|
||||
text-decoration-thickness: .1em;
|
||||
text-underline-offset: 1.5px; }
|
||||
figcaption a[href^="#"]:hover::selection,
|
||||
p a[href^="#"]:hover::selection,
|
||||
.page-tags a[href^="#"]:hover::selection,
|
||||
|
@ -1312,7 +1392,26 @@ dl a {
|
|||
#theme-switch:checked ~ #page #crosslinks a:not(.highlight):hover,
|
||||
#theme-switch:checked ~ #page li a:hover,
|
||||
#theme-switch:checked ~ #page dl a:hover {
|
||||
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg id='squiggle-link' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' xmlns:ev='http://www.w3.org/2001/xml-events' viewBox='0 0 20 4'%3E%3Cstyle type='text/css'%3E.squiggle{animation:shift .3s linear infinite;}@keyframes shift {from {transform:translateX(0);}to {transform:translateX(-20px);}}%3C/style%3E%3Cpath fill='none' stroke='%23ffffff' stroke-width='2' class='squiggle' d='M0,3.5 c 5,0,5,-3,10,-3 s 5,3,10,3 c 5,0,5,-3,10,-3 s 5,3,10,3'/%3E%3C/svg%3E"); }
|
||||
text-decoration: none; }
|
||||
#theme-switch:checked ~ #page #breadcrumbs a:hover::before,
|
||||
#theme-switch:checked ~ #page figcaption a:hover::before,
|
||||
#theme-switch:checked ~ #page p a:hover::before,
|
||||
#theme-switch:checked ~ #page .page-tags a:hover::before,
|
||||
#theme-switch:checked ~ #page table a:hover::before,
|
||||
#theme-switch:checked ~ #page #crosslinks a:not(.highlight):hover::before,
|
||||
#theme-switch:checked ~ #page li a:hover::before,
|
||||
#theme-switch:checked ~ #page dl a:hover::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
mask-image: url("data:image/svg+xml;charset=utf8,%3Csvg id='squiggle-link' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' xmlns:ev='http://www.w3.org/2001/xml-events' viewBox='0 0 20 4'%3E%3Cstyle type='text/css'%3E.squiggle{animation:shift .3s linear infinite;}@keyframes shift {from {transform:translateX(0);}to {transform:translateX(-20px);}}%3C/style%3E%3Cpath fill='none' stroke='%23000000' stroke-width='2' class='squiggle' d='M0,3.5 c 5,0,5,-3,10,-3 s 5,3,10,3 c 5,0,5,-3,10,-3 s 5,3,10,3'/%3E%3C/svg%3E") !important;
|
||||
mask-position: 0% 100%;
|
||||
mask-size: 0.8em auto;
|
||||
mask-repeat: repeat-x;
|
||||
background: var(--text-light); }
|
||||
|
||||
*:target::before {
|
||||
content: "🠖";
|
||||
|
@ -1330,12 +1429,12 @@ dl a {
|
|||
right: 0; } }
|
||||
#content .page-intro p a,
|
||||
#footnotes a {
|
||||
background-image: linear-gradient(var(--text-gray), var(--text-gray));
|
||||
background-size: 1px 1px;
|
||||
background-repeat: repeat-x;
|
||||
background-position: 0% 95%;
|
||||
border-radius: 1px;
|
||||
text-decoration: none; }
|
||||
text-decoration-line: underline;
|
||||
text-decoration-style: dotted;
|
||||
text-decoration-color: var(--text-light);
|
||||
text-decoration-thickness: .1em;
|
||||
text-underline-offset: 1.5px;
|
||||
border-radius: 1px; }
|
||||
#content .page-intro p a::selection,
|
||||
#footnotes a::selection {
|
||||
background: var(--back-medium); }
|
||||
|
@ -1353,12 +1452,12 @@ dl a {
|
|||
color: var(--text-gray); }
|
||||
#content .page-intro p a:hover,
|
||||
#footnotes a:hover {
|
||||
background-image: linear-gradient(var(--text-gray), var(--text-gray));
|
||||
background-size: 1px 1px;
|
||||
background-repeat: repeat-x;
|
||||
background-position: 0% 95%;
|
||||
border-radius: 1px;
|
||||
text-decoration: none; }
|
||||
text-decoration-line: underline;
|
||||
text-decoration-style: dotted;
|
||||
text-decoration-color: var(--text-light);
|
||||
text-decoration-thickness: .1em;
|
||||
text-underline-offset: 1.5px;
|
||||
border-radius: 1px; }
|
||||
#content .page-intro p a:hover::selection,
|
||||
#footnotes a:hover::selection {
|
||||
background: var(--back-medium); }
|
||||
|
@ -1444,6 +1543,7 @@ div.link-preview {
|
|||
max-height: 5em;
|
||||
padding-left: 0.5em; }
|
||||
div.link-preview a {
|
||||
color: inherit;
|
||||
text-decoration: none; }
|
||||
div.link-preview img {
|
||||
border-right: 1px solid var(--back-medium);
|
||||
|
@ -1452,7 +1552,7 @@ div.link-preview {
|
|||
margin-left: -0.5em;
|
||||
margin-right: 0.5em; }
|
||||
div.link-preview p {
|
||||
margin: 0;
|
||||
margin: 0 0.6em 0 0;
|
||||
font-size: 10pt; }
|
||||
div.link-preview p b {
|
||||
font-size: 11pt; }
|
||||
|
@ -1486,14 +1586,16 @@ ul li::before {
|
|||
|
||||
ol {
|
||||
counter-reset: li; }
|
||||
ol li:not([value]) {
|
||||
counter-increment: li; }
|
||||
ol li::before {
|
||||
content: counter(li);
|
||||
margin-left: -1.5em;
|
||||
margin-right: 0.5em;
|
||||
text-align: right;
|
||||
direction: rtl; }
|
||||
ol li {
|
||||
counter-increment: li; }
|
||||
ol li[value]::before {
|
||||
content: attr(value); }
|
||||
|
||||
ul ul, ol ol {
|
||||
padding-left: 20px; }
|
||||
|
@ -1786,6 +1888,7 @@ table {
|
|||
line-height: 1.9; }
|
||||
table caption {
|
||||
margin-bottom: 10px;
|
||||
min-width: 20em;
|
||||
font-family: "Open Sans", sans;
|
||||
font-weight: normal;
|
||||
font-size: 15px;
|
||||
|
|
|
@ -0,0 +1,293 @@
|
|||
#+title: February 2022
|
||||
#+subtitle: An orgmode clone for neovim
|
||||
#+author: Kristijan Husak
|
||||
#+date: 2022-02-30
|
||||
|
||||
Timothy (TEC) here. This month we have a guest post from a different part of the
|
||||
Org ecosystem, to highlight one of the most promising efforts to provide a good
|
||||
experience outside Emacs.
|
||||
|
||||
[[Https://github.com/nvim-orgmode/orgmode]]
|
||||
|
||||
"But I use Emacs, I don't care" you may say. In that case, I'd like to point out
|
||||
that wider spread and better Org support enriches the Org ecosystem as a whole.
|
||||
It makes the format more approachable, and /useful/ for other people. This is good
|
||||
for everybody.
|
||||
|
||||
Without any further ado, here's the guest post kindly written by Kristijan.
|
||||
Enjoy!
|
||||
|
||||
-----
|
||||
|
||||
Like every beginner Vim user, at some point I ran into a usual editor war post:
|
||||
Vim vs Emacs. At that time, I didn't have an idea what "Emacs" was.
|
||||
|
||||
A simple Google search yielded something that seemed just like a very simple
|
||||
editor with strange, but more familiar shortcuts. I didn't bother too much to
|
||||
figure out what it is, because I was already pulled in fairly deep into Vim and
|
||||
its philosophy.
|
||||
|
||||
* Note taking in (Neo)Vim
|
||||
|
||||
At first, I did some note taking only when really necessary, in random
|
||||
plain text files. Most of the things I managed to keep in my head, since
|
||||
I was younger and less busy 🙂.
|
||||
|
||||
Once I got into the situation where I needed to keep more notes, [[https://github.com/vimwiki/vimwiki][vimwiki]] was the
|
||||
natural choice.
|
||||
|
||||
That worked very well for a period, until the need for writing quick notes
|
||||
arise. Vimwiki didn't have anything that would allow that. I could of course
|
||||
have a mapping that opens a specific file where I can add notes, but that just
|
||||
never felt right in my mind. I would keep a bunch of things in the same place,
|
||||
and then later I needed to spend some time organizing them.
|
||||
|
||||
At that point, I wasn't sure how to achieve what I want. I did a brief look at
|
||||
[[https://orgmode.org/][Emacs OrgMode]] to see what's all the fuss about, but to me, it seemed just like a
|
||||
different version of Markdown. You put some unordered lists as your notes, and
|
||||
that's it. I never spent more time trying to see all the neat features. I even
|
||||
tried creating some of my custom note taking tools, but I never managed to
|
||||
finish them because I didn't have a clear idea of how to solve my problems.
|
||||
|
||||
* First encounter with Orgmode like tool: vim-dotoo
|
||||
|
||||
One weekend, I was browsing through Vim subreddit, as I usually do at least once
|
||||
a day. There was a post about an "Orgmode like task logging" plugin called
|
||||
[[https://github.com/dhruvasagar/vim-dotoo][vim-dotoo]]. I opened it up, and I didn't see much at that point. I wasn't too
|
||||
excited. I went through readme, and noticed that author ([[https://github.com/dhruvasagar][dhruvasagar]]) put a
|
||||
fairly big emphasis on the "Agenda view". I had no idea what "Agenda view" is.
|
||||
Thankfully, the author also made a [[https://www.youtube.com/watch?v=nsv33iOnH34][screencast]], which is rather long (1.5h), but
|
||||
I had some time, so I went through it.
|
||||
|
||||
At that point, I was first met with "Capturing" and "Refiling". *My mind was
|
||||
blown!* What a simple, yet extremely powerful idea! How had that never crossed my
|
||||
mind? From that point on, this plugin had my full attention.
|
||||
|
||||
I'm always emphasizing that [[https://github.com/dhruvasagar][dhruvasagar]] and his [[https://github.com/dhruvasagar/vim-dotoo][vim-dotoo]] plugin are most
|
||||
deserving for having inspired [[https://github.com/nvim-orgmode/orgmode]], and I
|
||||
can't thank him enough for that.
|
||||
|
||||
* First steps with vim-dotoo and birth of orgmode.nvim
|
||||
|
||||
For some time, I was using [[https://github.com/dhruvasagar/vim-dotoo][vim-dotoo]]. I moved all of my Vimwiki notes to it. It
|
||||
was a breath of fresh air. Alongside that, I started getting more interest in
|
||||
the original Emacs Orgmode. I started noticing the differences, and some of the
|
||||
missing features that were now looking quite attractive. I made [[https://github.com/dhruvasagar/vim-dotoo/pulls?q=is%3Apr+sort%3Aupdated-desc+author%3Akristijanhusak+is%3Aclosed][few
|
||||
contributions]] to vim-dotoo. As time passed, and my notes started to grow, things
|
||||
began being slow. I did some profiling, and figured out that it's just a usual
|
||||
Vim problem, Vimscript performance. It was just too slow for certain things that
|
||||
Orgmode provides, and it would hardly get any better as more things are added.
|
||||
|
||||
Separately from Vim and Vimscript, [[https://github.com/neovim/neovim][Neovim]] was on a stable =v0.4= release, and =v0.5=
|
||||
was still being developed. I was using Neovim from version 0.3, and was
|
||||
carefully following the progress on it. Lua was introduced as a first class
|
||||
citizen. A Bunch of new plugins arise from it. All the benchmarks showed that
|
||||
Lua outperforms Vimscript in almost everything. Besides the performance, Lua is
|
||||
a "normal" programming language, which means that support for it is much better.
|
||||
|
||||
At that point, I became curious: Could Lua be the path to the faster Orgmode? I
|
||||
spent several days thinking about it. I wanted to give it a try. My biggest
|
||||
concern was that I had absolutely zero experience writing parsers. I had never
|
||||
written anything more complicated than an averagely complicated regex for
|
||||
purposes of parsing. I noticed that vim-dotoo also used regex to do the parsing,
|
||||
so that eased my mind a bit.
|
||||
|
||||
One weekend, I started working on it. It was really interesting and challenging.
|
||||
I spent a lot of my free time on it. At certain points, it seemed like hacking,
|
||||
since it was not a proper parsing. I tried to learn how to write a proper
|
||||
parser, but it was just too time consuming and complicated. I proceeded with the
|
||||
regex parsing to see how far I can go.
|
||||
|
||||
Besides parsing, I had a few more challenges to overcome:
|
||||
|
||||
** Understanding the OrgMode syntax and all the functionality
|
||||
|
||||
This is still the biggest challenge. I didn't have any idea how big and robust
|
||||
OrgMode is. If I would know it at that time, I wouldn't even jump on this train.
|
||||
It's really hard to grasp all of it. Considering I've only used it for around 8
|
||||
months, I think I made some good progress on learning it.
|
||||
|
||||
** Remote editing
|
||||
|
||||
By remote editing, I mean automatically updating content in the current
|
||||
or any other file. Few examples: adding/updating properties, managing
|
||||
tags, changing TODO states, archiving, refiling, remote editing from
|
||||
agenda view, etc.
|
||||
|
||||
There is no built-in way to update content in another file through the
|
||||
Neovim API, without actually opening the file in an editor. I solved
|
||||
this by:
|
||||
|
||||
- Saving as much position information as possible in the internal state,
|
||||
so I can pinpoint the correct location
|
||||
- Opening a file in a =1 row x 1 col= floating window and doing quick
|
||||
edits there
|
||||
|
||||
** Working with dates
|
||||
|
||||
From my experience, dates are challenging in all areas of programming,
|
||||
so this is not so surprising. There are some Lua plugins for dates, but
|
||||
those seemed a bit too basic for my use case, and I wanted to keep
|
||||
external plugins to the minimum. I went with a custom solution that uses
|
||||
Lua's native dates, which has certain limitations, but works out for
|
||||
most of the things.
|
||||
|
||||
** Highlighting, mostly in Agenda view
|
||||
|
||||
Vim's syntax engine is fairly old, but still very much used, especially
|
||||
in the Vim community. Implementation of tree-sitter slightly improved
|
||||
this experience in Neovim, because "Highlight matches" are found via
|
||||
tree-sitter, instead of a bunch of regexes.
|
||||
|
||||
This helped me out later for the Org file itself, but agenda view is
|
||||
still something that's built as a custom view. Old Syntax highlight engine
|
||||
would be really hard to add, because the content is too dynamic. I went
|
||||
with the Neovim highlight API that allows Highlighting things by their
|
||||
exact position in the buffer. Tree-sitter implementation does something
|
||||
similar in the background for Highlighting.
|
||||
|
||||
** Keeping configuration simple and familiar to Emacs OrgMode
|
||||
|
||||
Vim-dotoo configuration was mostly Vim style, through some global
|
||||
variables. I wanted to have a configuration that is familiar to an Emacs
|
||||
OrgMode user, by having as many options as possible named completely the
|
||||
same as in Emacs.
|
||||
|
||||
For example, Here's a comparison of few options between Emacs and
|
||||
Neovim:
|
||||
|
||||
Emacs:
|
||||
|
||||
#+begin_src elisp
|
||||
(setq org-agenda-files '("~/orgmodes"))
|
||||
(setq org-agenda-skip-scheduled-if-done t)
|
||||
(setq org-agenda-span 7)
|
||||
(setq org-hide-leading-stars t)
|
||||
(setq org-capture-templates
|
||||
'(("t" "Todo" entry (file "~/orgmodes/todos.org")
|
||||
"* TODO %?")
|
||||
("j" "Journal" entry (file "~/orgmodes/journal.org")
|
||||
"* %?\nEntered on %U\n %a")))
|
||||
#+end_src
|
||||
|
||||
Neovim:
|
||||
|
||||
#+begin_src lua
|
||||
require('orgmode').setup({
|
||||
org_agenda_files = { '~/orgmodes' },
|
||||
org_agenda_skip_scheduled_if_done = true,
|
||||
org_agenda_span = 7,
|
||||
org_hide_leading_stars = true
|
||||
org_capture_templates = {
|
||||
t = {
|
||||
description = 'Todo',
|
||||
target = '~/orgmodes/todos.org',
|
||||
template = '* TODO %?',
|
||||
},
|
||||
j = {
|
||||
description = 'Journal',
|
||||
target = '~/orgmodes/journal.org',
|
||||
template = '* %?\nEntered on %U\n %a',
|
||||
}
|
||||
}
|
||||
})
|
||||
#+end_src
|
||||
|
||||
One of the most noticeable differences is between the usage of hyphens
|
||||
(=-=) and underscores (=_=). I did that only for the sake of simplicity,
|
||||
because hyphens is not a valid character in variable names in Lua, so
|
||||
all of the options would need to be wrapped as a string (for example:
|
||||
=['org-agenda-files']=).
|
||||
|
||||
* First release of orgmode.nvim and introduction of tree-sitter parser
|
||||
|
||||
After ~1.5 months I [[https://www.reddit.com/r/neovim/comments/o8zp0k/orgmodenvim_orgmode_clone_written_in_lua_for/][published the initial version]]. The focus was on Agenda and
|
||||
capturing (GTD), since those are the things I mostly used. It got some traction,
|
||||
and people started testing it and reporting bugs.
|
||||
|
||||
One of the common questions was: /"Any plans to introduce tree-sitter parser?"/.
|
||||
|
||||
I knew about [[https://github.com/tree-sitter/tree-sitter][tree-sitter]] and used it in my day-to-day job for a few programming
|
||||
languages, but I had absolutely no idea how it worked, and especially how to
|
||||
write a tree-sitter parser. I put it aside, and continued working on what I
|
||||
had.
|
||||
|
||||
One day, Emilia ([[https://github.com/milisims][milisims]]) contacted me via email to ask me if I would be
|
||||
willing to try the tree-sitter parser she's been working on for some time. I
|
||||
gladly accepted. She gave me access to the repository, and I started tinkering
|
||||
with it in a separate branch. No one was aware at that point that tree-sitter
|
||||
support would happen some time soon.
|
||||
|
||||
After some time, I set up a "beta" branch called "tree-sitter" and [[https://www.reddit.com/r/neovim/comments/ph2xqc/orgmodenvim_treesitter_support/][announced it
|
||||
for testing]]. Once the reported bugs slowed to a trickle, I merged it into the
|
||||
"master" branch.
|
||||
|
||||
I believe that tree-sitter grammar for Org could help out other editors to
|
||||
implement their version of Orgmode plugin, but I don't think it would ever be
|
||||
helpful for Emacs. Emacs parser is the one and only that has it all implemented.
|
||||
Also, as much as tree-sitter is powerful, its main purpose is to parse
|
||||
programming languages, which mostly has "static" patterns to match. Orgmode is
|
||||
by its nature dynamic, which causes a variety of issues for a parser that's not
|
||||
meant for that kind of usage.
|
||||
|
||||
* Limitations
|
||||
|
||||
(Neo)Vim is a great editor, but it still cannot compare to Emacs in certain
|
||||
things. Manipulating the "View" part of the editor is tricky or impossible for
|
||||
certain things.
|
||||
|
||||
I even [[https://github.com/nvim-orgmode/orgmode/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Aneovim-dependency][made a label]] for reported issues where Neovim support for certain things
|
||||
is a blocker. I'm hoping that at least some of these will be available in future
|
||||
Neovim releases.
|
||||
|
||||
* Features
|
||||
|
||||
I will not go into too many details about the available features, since those
|
||||
can be viewed in [[https://github.com/nvim-orgmode/orgmode#features-detailed-breakdown][repository readme]], but I want to mention one feature that does
|
||||
not exist as a built/-in feature in the Emacs Orgmode: [[https://github.com/nvim-orgmode/orgmode/blob/master/DOCS.md#notifications-experimental][Notifications]].
|
||||
|
||||
This allows getting a "desktop notification" for tasks that are within
|
||||
the specified threshold for schedule/deadline time. It requires some
|
||||
configuration to set up a cron job, but it's been working great for me
|
||||
for several months now.
|
||||
|
||||
* Plans
|
||||
|
||||
The current state of the project is very usable for me. I'm not lacking any of
|
||||
the major features, mostly because I'm not used to using them. Nevertheless,
|
||||
there are plans to add more things, and I'm getting a lot of help from the
|
||||
community. I want to specifically mention [[https://github.com/levouh][levouh]] and [[https://github.com/lukas-reineke][lukas-reineke]], since they
|
||||
added a lot of value to the project, and I want to thank them and everyone else
|
||||
who contributed. Their help is much appreciated.
|
||||
|
||||
There are few high priority tasks that I'm hoping to flush out first:
|
||||
|
||||
- Implementing [[https://github.com/milisims/tree-sitter-org/issues/13][v1.0.0]] release of the tree-sitter parser. This should allow for
|
||||
faster and less error-prone parsing.
|
||||
- [[https://github.com/nvim-orgmode/orgmode/issues/26][Infrastructure for plugin developers]], to allow other people to build plugins
|
||||
on top of nvim-orgmode.
|
||||
|
||||
And a long term goal for these:
|
||||
|
||||
- Tables support (and at least basic formulas)
|
||||
- [[https://github.com/nvim-orgmode/orgmode/issues/190][Org Babel like code block evaluation]] (and hopefully basic support for literate
|
||||
programming)
|
||||
- [[https://github.com/nvim-orgmode/orgmode/issues/195][Diary format dates]]
|
||||
- [[https://github.com/nvim-orgmode/orgmode/issues/135][Custom agenda commands]]
|
||||
- More clocking features (reports)
|
||||
- File specific configuration via directives ([[https://github.com/nvim-orgmode/orgmode/issues/185][todo keywords]], properties, etc.)
|
||||
|
||||
* Closing thoughts
|
||||
|
||||
When I started working on [[https://github.com/nvim-orgmode/orgmode][nvim-orgmode]], I didn't have a clue what I'm jumping
|
||||
into. Every day I learn about more and more Orgmode features that I wasn't even
|
||||
aware existed.
|
||||
|
||||
I'm certain that this project will never manage to clone the Orgmode
|
||||
functionality completely, but I'm hoping it will get close enough so everyone
|
||||
from Neovim community and Emacsers trying out Neovim will be able to use it for
|
||||
their needs.
|
||||
|
||||
Having experienced Orgmode users [[https://github.com/nvim-orgmode/orgmode/issues/159][testing]] it is a huge help, so if anyone is
|
||||
willing to give it a try, feel free to open up an issue and write your thoughts
|
||||
there. Thanks!
|
|
@ -0,0 +1,41 @@
|
|||
#+title: Special Announcement
|
||||
#+subtitle: Throwing in the towel and jumping on the bandwagon
|
||||
#+author: TEC
|
||||
#+date: 2022-04-01
|
||||
|
||||
It *h*as become apparent to the Org Mode developers that Org is suffering from a
|
||||
severe lack of enterprise adoption. To r*e*ctify this, we will be leveraging our
|
||||
collective decades working on holistic human-markup interaction tools to rapid*l*y
|
||||
pivot to what we believe to be the /true/ markup format of the future ---
|
||||
[[https://confluence.atlassian.com/doc/confluence-wiki-markup-251003035.html][Confluence Wiki Markup]].
|
||||
|
||||
With this *p*aradigm shift, you can look forward to a much more intuitive syntax,
|
||||
empowering you to create next-generation agile documents.
|
||||
|
||||
To assist you in this *t*ransition, we'll give you a brief overview of the changes
|
||||
you can expect. Text formatting is almost unaffected, with a few sensible
|
||||
changes made to the surrounding c*h*aracters.
|
||||
|
||||
#+caption: Translation between Org's syntax and our new Confluence overlords's equivalents
|
||||
#+attr_html: :class invertible
|
||||
[[file:figures/org-markup-to-confluence.svg]]
|
||||
|
||||
We'd like to thank the FSF for giving the Org project the space and support to
|
||||
grow to become a world-class proj*e*ct. In our new venture, cop*y*right assignment
|
||||
to t*h*e FSF is no longer required. Inste*a*d, copyright must be assigned to
|
||||
Atlassian prior to contributing.
|
||||
|
||||
This new partnership enables new and exciting integrations with Atlassian's
|
||||
proprietary technologies. O*v*er the next f*e*w months we will *b*e transforming Org
|
||||
to a cloud-n*a*tive serverless profes*s*ional markup offering. Unlike Confluence, we
|
||||
will allow you to bo*t*h write /and edit/ documents using pla*i*ntext markup. We
|
||||
believe that by unlocking the synergy between plaintext and Confluence the Org
|
||||
project will become a thought leader in hyp*e*r-scale markup solutions.
|
||||
|
||||
The shift to Confluence wiki markup will come as a surprise to many of you, but
|
||||
after doing a deep dive into the scalability of Org we realised that there were
|
||||
no low-hanging fruit available --- only out of the box thinking will allow for the
|
||||
in*n*ovation so many of our users crave.
|
||||
|
||||
We hope this change will not just disrupt your documents, but the entire markup
|
||||
industry.
|
|
@ -0,0 +1,224 @@
|
|||
# -*- org-plot/gnuplot-term-extra: "background rgb '#fafafa' size 800,500 font 'Alegreya Sans, 16'"; -*-
|
||||
#+title: May 2022
|
||||
#+subtitle: Folding more improvement into Org
|
||||
#+author: TEC
|
||||
#+date: 2022-05-31
|
||||
|
||||
Finding time as of late has been more difficult than I anticipated, and on top
|
||||
of that, just as I was thinking of writing last month's post, I got distracted
|
||||
by an exciting patchset that has been in the works for over a year finally
|
||||
getting sorted out and landing. So, I hope that some of the fun developments in
|
||||
this post will make up the absense of the last one 🙂.
|
||||
|
||||
Since it's been longer than I thought since the last standard post, we've got a
|
||||
fair few commits to catch up on --- about 200. Most of these are miscellaneous
|
||||
minor improvements and bugfixes, but a few notable changes have arrived too.
|
||||
|
||||
* Folding
|
||||
|
||||
The fabulous new folding engine (=org-fold-core=) should noticeably improve Org's
|
||||
performance with large files. It contains a number of key optimisations to
|
||||
improve speed, namely:
|
||||
+ Deferring fontification of folded regions
|
||||
+ Using text properties (\(\mathcal{O}(n \log n)\)) instead of overlays (\(\mathcal{O}(n^2)\)) for folded regions
|
||||
+ A collection of aggressive optimisations available under ~org-fold-core--optimise-for-huge-buffers~
|
||||
+ Convert text properties to overlays for =isearch= (which currently only supports overlays)
|
||||
|
||||
How noticeable is the overall performance impact? Well, I poked Ihor and he was
|
||||
kind enough to whip up some benchmarks.
|
||||
|
||||
#+caption: The scaling of ~org-shifttab~ showing file contents, as file size increases, with and without org-fold.
|
||||
#+attr_html: :class invertible
|
||||
[[file:figures/org-fold-perf-shifttab-contents.svg]]
|
||||
|
||||
#+caption: The scaling of ~org-shifttab~ showing the entire file, as file size increases, with and without org-fold.
|
||||
#+attr_html: :class invertible
|
||||
[[file:figures/org-fold-perf-shifttab-showall.svg]]
|
||||
|
||||
Well this looks very promising[fn::Note the difference in scale, org-fold makes
|
||||
the most difference in the graph where the times are an order of magnitude
|
||||
more.]! Let's see how much of an improvement this is overall.
|
||||
|
||||
#+caption: Time to run =org-shifttab= twice, cycling through all three display modes (in seconds).
|
||||
| File size (Mb) | Headings (thousands) | Bugfix (no org-fold) | Main (with org-fold) | Improvement |
|
||||
|----------------+----------------------+----------------------+----------------------+-------------|
|
||||
| 18 | 36 | 115.31 | 0.89 | 99% |
|
||||
| 8.8 | 24 | 19.03 | 0.48 | 97% |
|
||||
| 4.4 | 5 | 3.79 | 0.13 | 97% |
|
||||
| 2.2 | 2 | 1.29 | 0.08 | 94% |
|
||||
| 1.1 | 1 | 0.50 | 0.045 | 91% |
|
||||
#+TBLFM: $5=100*(1 - $4/$3) ; %.0f%%
|
||||
|
||||
To be clear, even the smallest file in this data --- a 1.1 Mb Org file with around
|
||||
a thousand headings, is fairly large. So, it's unlikely you'll notice much of a
|
||||
difference with small--medium files, but if you a few large+ files this should
|
||||
be a /fantastic/ improvement. Once again, thanks Ihor!
|
||||
|
||||
#+begin_warning
|
||||
The change to text properties instead of overlays breaks a number of third party
|
||||
packages like =evil-search= and =consult='s ~consult-line~.
|
||||
If you are involved in any packages affected by this, you'll either want to
|
||||
consider supporting invisible text, or look at ~isearch-filter-predicate~ and
|
||||
~isearch-mode-end-hook~, which =org-fold= now uses.
|
||||
If you're an end-user, perhaps politely make an issue on the repo for a project
|
||||
/if no issue currently exists/, and either:
|
||||
+ Stay off Org's bleeding edge till the package ecosystem has adapted to this change
|
||||
+ Help the packages you use adapt to this change
|
||||
+ Set ~org-fold-core-style~ to ~overlays~ to restore the old behaviour
|
||||
#+end_warning
|
||||
|
||||
** Benchmark data :noexport:
|
||||
|
||||
#+plot: ind:2 deps:(3 4) with:linespoints file:"figures/org-fold-perf-shifttab-contents.svg"
|
||||
#+plot: set:"title '{/*1.6 Running org-shifttab to CONTENTS}'" set:"xlabel '{/*1.2 File size (Mb)}'" set:"ylabel '{/*1.2 Load time (seconds)}'"
|
||||
#+plot: set:"logscale x" set:"logscale y" set:"linetype 1 pt 5" set:"linetype 2 pt 7"
|
||||
| Headings (k) | File Size (Mb) | Bugfix (no org-fold) | Main (org-fold) |
|
||||
|--------------+----------------+----------------------+-----------------|
|
||||
| 217 | 150 | 173.28 | 10.73 |
|
||||
| 36 | 18 | 1.97 | 0.92 |
|
||||
| 24 | 8.8 | 0.81 | 0.46 |
|
||||
| 5 | 4.4 | 0.09 | 0.21 |
|
||||
| 2 | 2.2 | 0.03 | 0.07 |
|
||||
| 1 | 1.1 | 0.02 | 0.04 |
|
||||
|
||||
#+plot: ind:2 deps:(3 4) with:linespoints file:"figures/org-fold-perf-shifttab-showall.svg"
|
||||
#+plot: set:"title '{/*1.6 Running org-shifttab to SHOW-ALL}'" set:"xlabel '{/*1.2 File size (Mb)}'" set:"ylabel '{/*1.2 Load time (seconds)}'"
|
||||
#+plot: set:"logscale x" set:"logscale y" set:"linetype 1 pt 5" set:"linetype 2 pt 7"
|
||||
| Headings (k) | File Size (Mb) | Bugfix (no org-fold) | Main (org-fold) |
|
||||
|--------------+----------------+----------------------+-----------------|
|
||||
| 217 | 150 | 8921.02 | 0.09 |
|
||||
| 36 | 18 | 100.96 | 0.02 |
|
||||
| 24 | 8.8 | 17.35 | 0.01 |
|
||||
| 5 | 4.4 | 3.79 | 0.005 |
|
||||
| 2 | 2.2 | 1.20 | 0.003 |
|
||||
| 1 | 1.1 | 0.49 | 0.003 |
|
||||
|
||||
* /Engraved/ source code blocks in LaTeX
|
||||
|
||||
All too often exporting code to LaTeX has been a disappointment, with lovely
|
||||
syntax highlighting from Emacs major modes replaced with a markedly inferior
|
||||
attempt by pygments (setting ~org-latex-listings~ to ~minted~) in a colour scheme I
|
||||
don't really like.
|
||||
|
||||
A bit over a year ago, a project called [[https://github.com/tecosaur/engrave-faces][engrave-faces]] started with the aim of
|
||||
making Emacs' font-lock more exportable, like a generalised =htmlize.el=. This has
|
||||
recently been used to provide a new option for inline and block source code
|
||||
exports in LaTeX.
|
||||
|
||||
#+caption: A screenshot of an Org code block, exported to a PDF,
|
||||
#+caption: using =engrave-faces= and the =doom-one-light= theme.
|
||||
#+attr_html: :class invertible
|
||||
[[file:figures/engraved-faces-sample.png]]
|
||||
|
||||
To use this, simply install the package and set ~org-latex-src-block-backend~ (a
|
||||
rename of ~org-latex-listings~ to better reflect its usage) to ~engraved~.
|
||||
|
||||
While this is sufficient to get started, this new backend also allows for some
|
||||
new options. The theme used for /engraving/ a source block can be set globally
|
||||
with the new variable ~org-latex-engraved-theme~, or per-file with the
|
||||
=#+latex_engraved_theme= keyword. It takes either the name of a theme, or the
|
||||
symbol =t= as a stand-in for the current theme.
|
||||
|
||||
The theme can also be set on a per-block level using the LaTeX attribute
|
||||
=:engraved-theme=.
|
||||
|
||||
#+caption: Seven code blocks exported to LaTeX, each with a different engrave-faces theme.
|
||||
[[file:figures/engraved-faces-multitheme.png]]
|
||||
|
||||
Here's what using these new capabilities looks like in practice.
|
||||
|
||||
#+begin_src org
|
||||
,#+title: Engraving source blocks
|
||||
,#+latex_engraved_theme: modus-operandi
|
||||
|
||||
,#+begin_src emacs-lisp
|
||||
(message "look ma, some %s" 'code)
|
||||
,#+end_src
|
||||
|
||||
,#+attr_latex: :engraved-theme modus-viviandi
|
||||
,#+begin_src shell
|
||||
echo "This is shell code"
|
||||
,#+end_src
|
||||
#+end_src
|
||||
|
||||
This may well be the best syntax-highlighting solution available for PDFs/LaTeX
|
||||
currently available, but I am a tad biased 😛.
|
||||
|
||||
* TexInfo export improvements
|
||||
|
||||
Jonas Bernoulli has been using a custom TexInfo backend for Magit's
|
||||
documentation for a while now, and over the past few months he's worked the
|
||||
features he was missing into Org's built-in TexInfo exporter.
|
||||
|
||||
Upstreaming like this always takes a fair bit of effort, so thank you Jonas for
|
||||
going through with this!
|
||||
|
||||
* Toggle noweb prefix handling
|
||||
|
||||
Previously, whenever a noweb reference appeared on a non-empty line, a
|
||||
multi-line replacement would duplicate the content before the noweb reference.
|
||||
|
||||
Clearly, this is not always desirable, and this behaviour can now be turned of
|
||||
by setting the new header argument =:noweb-prefix no=.
|
||||
|
||||
#+begin_src org
|
||||
,#+begin_src emacs-lisp :noweb yes :noweb-prefix no
|
||||
(setq example-data "<<example>>")
|
||||
,#+end_src
|
||||
|
||||
Will now expand to
|
||||
|
||||
,#+begin_src emacs-lisp
|
||||
(setq example-data "some
|
||||
multi-line
|
||||
content")
|
||||
,#+end_src
|
||||
|
||||
Instead of
|
||||
|
||||
,#+begin_src emacs-lisp
|
||||
(setq example-data "some
|
||||
(setq example-data "multiline
|
||||
(setq example-data "content")
|
||||
,#+end_src
|
||||
#+end_src
|
||||
|
||||
* Package highlight: org-modern
|
||||
I think we've all [[https://github.com/integral-dw/org-superstar-mode][seen]] [[https://github.com/sabof/org-bullets][plenty]] of =org-mode= [[https://github.com/Fuco1/org-pretty-table][prettification]] [[https://github.com/harrybournis/org-fancy-priorities][packages]] [[https://gitlab.com/marcowahl/org-pretty-tags][before]], so
|
||||
what makes Minad's [[https://github.com/minad/org-modern][org-modern]] special? It's actually doing something similar to
|
||||
Ihor's org-fold improvements, switching out slower overlay-based approaches for
|
||||
text properties. I can confirm that switching out =org-superstar-mode= for
|
||||
=org-modern= has made a substantial improvement in my experience, halving the
|
||||
first-load time of my =config.org= to around 20 seconds. If you're a fan of Org
|
||||
prettification and haven't taken a look at this package, I highly recommend
|
||||
giving it a shot.
|
||||
|
||||
#+caption: A demonstration of org-modern taken from the project README.
|
||||
#+attr_html: :class invertible
|
||||
[[file:figures/org-modern-readme-demo.gif]]
|
||||
|
||||
* Other improvements
|
||||
+ Clean up some magic numbers in =org-attach= _Marco Wahl_
|
||||
+ Allow /any/ command form in ~org-attach-commands~ (including keyboard macros)
|
||||
_Marco Wahl_
|
||||
+ Allow =dest= in ~org-list-send-item~ to be a buffer position _Sacha Chua_
|
||||
+ Improve CSL-JSON date handling in =oc-basic= _David Lukes_
|
||||
+ Add =TOML= and =desktop= language aliases _TEC_
|
||||
+ Speed up cached bibliography retrieval in =oc-basic= _Ihor Radchenko_
|
||||
+ Allow setting PlantUML jar arguments _Ihor Radchenko_
|
||||
+ Allow for customisation of property separators with ~org-property-separators~
|
||||
_Tyler Grinn_
|
||||
+ New =ox-latex= maintainer, Daniel Fleischer
|
||||
+ More unit tests _Kyle Keyer, Nick Dokos_
|
||||
+ Documentation improvements _Kyle Meyer, Juan Manuel Macias, Bastien, Karl
|
||||
Fogel, Cody Harris_
|
||||
|
||||
* Bugfixes
|
||||
+ An Emacs <28 bug in =org-persist= _Ihor Radchenko_
|
||||
+ Author extraction in =oc-basic= _Nicolas Goaziou_
|
||||
+ Fix behaviour of ~org-copy-visible~ with adjacent tex and
|
||||
~buffer-invisibility-spec~ _Kyle Meyer_
|
||||
+ Parsing of inline footnotes with parentheses _Nicolas Goaziou_
|
||||
+ Honor ~default-directory~ in =ob-gnuplot= _Ihor Radchenko_
|
||||
+ Heading fontification bug _Anders Johansson_
|
||||
+ Template expansion where one key is a substring of another _Andrew Arensburger_
|
|
@ -0,0 +1,56 @@
|
|||
;;; engraved-theme.el -*- lexical-binding: t; -*-
|
||||
|
||||
(require 'engrave-faces)
|
||||
|
||||
(add-to-list 'engrave-faces-themes
|
||||
'(doom-opera-light
|
||||
(default :short "default" :slug "D" :family "JetBrains Mono" :foreground "#2a2a2a" :background "#fafafa" :slant normal :weight regular)
|
||||
(bold :short "bold" :slug "b" :weight bold)
|
||||
(italic :short "italic" :slug "i" :slant italic)
|
||||
(variable-pitch :short "var-pitch" :slug "vp" :family "Overpass" :height 196)
|
||||
(shadow :short "shadow" :slug "h" :foreground "#9e9e9e")
|
||||
(success :short "success" :slug "sc" :foreground "#4f894c")
|
||||
(warning :short "warning" :slug "w" :foreground "#9a7500")
|
||||
(error :short "error" :slug "e" :foreground "#99324b")
|
||||
(link :short "link" :slug "l" :foreground "#3b6ea8" :weight bold)
|
||||
(link-visited :short "link" :slug "lv" :foreground "#8b008b" :weight bold)
|
||||
(highlight :short "link" :slug "hi" :foreground "#fafafa" :background "#3b6ea8")
|
||||
(font-lock-comment-face :short "fl-comment" :slug "c" :foreground "#b1b1b1")
|
||||
(font-lock-comment-delimiter-face :short "fl-comment-delim" :slug "cd" :foreground "#b1b1b1")
|
||||
(font-lock-string-face :short "fl-string" :slug "s" :foreground "#4f894c")
|
||||
(font-lock-doc-face :short "fl-doc" :slug "d" :foreground "#b6b6b6")
|
||||
(font-lock-doc-markup-face :short "fl-doc-markup" :slug "m" :foreground "#97365b")
|
||||
(font-lock-keyword-face :short "fl-keyword" :slug "k" :foreground "#3b6ea8")
|
||||
(font-lock-builtin-face :short "fl-builtin" :slug "bi" :foreground "#29838d")
|
||||
(font-lock-function-name-face :short "fl-function" :slug "f" :foreground "#29838d")
|
||||
(font-lock-variable-name-face :short "fl-variable" :slug "v" :foreground "#cb9aad")
|
||||
(font-lock-type-face :short "fl-type" :slug "t" :foreground "#9a7500")
|
||||
(font-lock-constant-face :short "fl-constant" :slug "o" :foreground "#97365b")
|
||||
(font-lock-warning-face :short "fl-warning" :slug "wr" :foreground "#9a7500")
|
||||
(font-lock-negation-char-face :short "fl-neg-char" :slug "nc" :foreground "#3b6ea8" :weight bold)
|
||||
(font-lock-preprocessor-face :short "fl-preprocessor" :slug "pp" :foreground "#3b6ea8" :weight bold)
|
||||
(font-lock-regexp-grouping-construct :short "fl-regexp" :slug "rc" :foreground "#3b6ea8" :weight bold)
|
||||
(font-lock-regexp-grouping-backslash :short "fl-regexp-backslash" :slug "rb" :foreground "#3b6ea8" :weight bold)
|
||||
(org-block :short "org-block" :slug "ob" :background "#e0e0e0")
|
||||
(org-block-begin-line :short "org-block-begin" :slug "obb" :foreground "#b1b1b1" :background "#e0e0e0")
|
||||
(org-block-end-line :short "org-block-end" :slug "obe" :foreground "#b1b1b1" :background "#e0e0e0")
|
||||
(outline-1 :short "outline-1" :slug "Oa" :foreground "#3b6ea8" :weight extra-bold :height 1.25)
|
||||
(outline-2 :short "outline-2" :slug "Ob" :foreground "#97365b" :weight bold :height 1.15)
|
||||
(outline-3 :short "outline-3" :slug "Oc" :foreground "#842879" :weight bold :height 1.12)
|
||||
(outline-4 :short "outline-4" :slug "Od" :foreground "#6c92bd" :weight semi-bold :height 1.09)
|
||||
(outline-5 :short "outline-5" :slug "Oe" :foreground "#b16883" :weight semi-bold :height 1.06)
|
||||
(outline-6 :short "outline-6" :slug "Of" :foreground "#9db6d3" :weight semi-bold :height 1.03)
|
||||
(outline-7 :short "outline-7" :slug "Og" :foreground "#cb9aad" :weight bold)
|
||||
(outline-8 :short "outline-8" :slug "Oh" :foreground "#d7e2ed" :weight semi-bold)
|
||||
(highlight-numbers-number :short "hl-number" :slug "hn" :foreground "#97365b" :weight bold)
|
||||
(highlight-quoted-quote :short "hl-qquote" :slug "hq" :foreground "#3b6ea8")
|
||||
(highlight-quoted-symbol :short "hl-qsymbol" :slug "hs" :foreground "#9a7500")
|
||||
(rainbow-delimiters-depth-1-face :short "rd-1" :slug "rda" :foreground "#3b6ea8")
|
||||
(rainbow-delimiters-depth-2-face :short "rd-2" :slug "rdb" :foreground "#97365b")
|
||||
(rainbow-delimiters-depth-3-face :short "rd-3" :slug "rdc" :foreground "#4f894c")
|
||||
(rainbow-delimiters-depth-4-face :short "rd-4" :slug "rdd" :foreground "#842879")
|
||||
(rainbow-delimiters-depth-5-face :short "rd-5" :slug "rde" :foreground "#29838d")
|
||||
(rainbow-delimiters-depth-6-face :short "rd-6" :slug "rdf" :foreground "#3b6ea8")
|
||||
(rainbow-delimiters-depth-7-face :short "rd-7" :slug "rdg" :foreground "#97365b")
|
||||
(rainbow-delimiters-depth-8-face :short "rd-8" :slug "rdh" :foreground "#4f894c")
|
||||
(rainbow-delimiters-depth-9-face :short "rd-9" :slug "rdi" :foreground "#842879")))
|
|
@ -1,77 +0,0 @@
|
|||
#!/usr/bin/env sh
|
||||
":"; exec script -eqfc "TERM=xterm-direct emacs --quick -nw --eval '(progn (setq file-to-htmlize \"$1\" output-file \"$2\") (load (expand-file-name \"$0\")))' && rm typescript" 1>/dev/null # -*- mode: emacs-lisp; lexical-binding: t; -*-
|
||||
|
||||
(defvar htmlize-theme 'doom-opera-light)
|
||||
|
||||
;; Need output file
|
||||
(when (string= "" output-file)
|
||||
(kill-emacs 2))
|
||||
(setq output-file (expand-file-name output-file))
|
||||
|
||||
;;; Doom initialisation
|
||||
|
||||
(unless (bound-and-true-p doom-init-p)
|
||||
(setq gc-cons-threshold 16777216
|
||||
gcmh-high-cons-threshold 16777216)
|
||||
(setq doom-disabled-packages '(doom-themes))
|
||||
(load (expand-file-name "core/core.el" user-emacs-directory) nil t)
|
||||
(require 'core-cli)
|
||||
(doom-initialize))
|
||||
|
||||
(advice-add 'undo-tree-mode :override #'ignore) ; Undo tree is a pain
|
||||
|
||||
(load-theme htmlize-theme t)
|
||||
|
||||
;;; No recentf please
|
||||
|
||||
(recentf-mode -1)
|
||||
(advice-add 'recentf-mode :override #'ignore)
|
||||
(advice-add 'recentf-cleanup :override #'ignore)
|
||||
|
||||
;;; Writegood is not desired
|
||||
|
||||
(advice-add 'writegood-mode :override #'ignore)
|
||||
|
||||
;;; Quit without fuss
|
||||
|
||||
(setq kill-emacs-hook nil
|
||||
noninteractive t)
|
||||
|
||||
;;; Lighten org-mode
|
||||
|
||||
(when (string= "org" (file-name-extension file-to-htmlize))
|
||||
(setcdr (assoc 'org after-load-alist) nil)
|
||||
(setq org-load-hook nil)
|
||||
(require 'org)
|
||||
(setq org-mode-hook nil))
|
||||
|
||||
;; Start htmlizing
|
||||
|
||||
(require 'htmlize)
|
||||
|
||||
(ignore-errors
|
||||
(with-temp-buffer
|
||||
(insert-file-contents file-to-htmlize)
|
||||
(setq buffer-file-name file-to-htmlize)
|
||||
(ignore-errors
|
||||
(normal-mode)
|
||||
(if (eq major-mode 'org-mode)
|
||||
(org-show-all))
|
||||
(font-lock-ensure))
|
||||
(with-current-buffer (htmlize-buffer-1)
|
||||
(goto-char (point-min))
|
||||
(replace-string "</title>\n"
|
||||
"</title>
|
||||
<style>
|
||||
body { background: #f0eeed !important; }
|
||||
body > pre {
|
||||
font-size: 1rem;
|
||||
max-width: min(100rem, 100%);
|
||||
width: max-content;
|
||||
white-space: pre-wrap;
|
||||
margin: auto;
|
||||
}
|
||||
</style>\n")
|
||||
(write-file output-file)
|
||||
(kill-emacs 0))))
|
||||
(kill-emacs 1)
|
260
publish.el
260
publish.el
|
@ -1,35 +1,109 @@
|
|||
#!/usr/bin/env sh
|
||||
":"; exec emacs --quick --script "$0" -- "$@" # -*- mode: emacs-lisp; lexical-binding: t; -*-
|
||||
|
||||
(message "Publising")
|
||||
(if load-file-name
|
||||
(message "Publising")
|
||||
(error "This is designed to be run as a script file, not within Emacs"))
|
||||
|
||||
(defvar force nil) ; -f --force
|
||||
(defvar update-commit nil) ; -u --update
|
||||
(defvar update-draft nil) ; -d --draft
|
||||
|
||||
(pop argv) ; $0
|
||||
(setq force (string= "-f" (pop argv)))
|
||||
|
||||
;;; Doom initialisation
|
||||
(while argv
|
||||
(pcase (pop argv)
|
||||
((or "-f" "--force")
|
||||
(setq force t))
|
||||
((or "-u" "--update")
|
||||
(setq update-commit t))
|
||||
((or "-d" "--draft")
|
||||
(setq update-draft t))))
|
||||
|
||||
(unless (bound-and-true-p doom-init-p)
|
||||
(setq gc-cons-threshold 16777216
|
||||
gcmh-high-cons-threshold 16777216)
|
||||
(setq doom-disabled-packages '(doom-themes))
|
||||
(load (expand-file-name "core/core.el" user-emacs-directory) nil t)
|
||||
(require 'core-cli)
|
||||
(doom-initialize))
|
||||
(when (and update-commit update-draft)
|
||||
(warn! "--update and --draft are mutually exclusive, --draft will take priority"))
|
||||
|
||||
(advice-add 'undo-tree-mode :override #'ignore) ; Undo tree is a pain
|
||||
(setq gc-cons-threshold (* 4 1024 1024)
|
||||
gcmh-high-cons-threshold (* 4 1024 1024))
|
||||
|
||||
;;; Package initialisation
|
||||
|
||||
(unless (file-directory-p "~/.config/doom")
|
||||
(error "This publishing script currently assumes a Doom emacs install exists."))
|
||||
|
||||
;; Assumes that the doom install is already fully-functional.
|
||||
(push "~/.config/emacs/lisp" load-path)
|
||||
(push "~/.config/emacs/lisp/lib" load-path)
|
||||
(require 'doom-lib)
|
||||
(require 'doom)
|
||||
(doom-require 'doom-lib 'files)
|
||||
(require 'doom-modules)
|
||||
(require 'doom-packages)
|
||||
(doom-initialize-packages)
|
||||
|
||||
;;I don't like this, but it works.
|
||||
(dolist (subdir (directory-files (file-name-concat straight-base-dir "straight" straight-build-dir) t))
|
||||
(push subdir load-path))
|
||||
|
||||
(require 'doom-cli)
|
||||
(doom-require 'doom-cli 'doctor)
|
||||
|
||||
(doom-module-context-with '(:config . use-package)
|
||||
(doom-load (abbreviate-file-name
|
||||
(file-name-sans-extension
|
||||
(doom-module-locate-path :config 'use-package doom-module-init-file)))))
|
||||
|
||||
(defun doom-shut-up-a (fn &rest args)
|
||||
;;`quiet!' is defined in doom-lib.el
|
||||
(quiet! (apply fn args)))
|
||||
|
||||
(push "~/.config/doom/subconf" load-path)
|
||||
|
||||
;;; General publishing setup
|
||||
|
||||
(section! "Initialising")
|
||||
|
||||
(require 'org)
|
||||
(require 'ox-publish)
|
||||
(require 'ox-html)
|
||||
(require 'ox-latex)
|
||||
(require 'ox-ascii)
|
||||
(require 'ox-org) ; For the word count
|
||||
(require 'org-persist)
|
||||
(remove-hook 'kill-emacs-hook #'org-persist-gc)
|
||||
|
||||
(setq site-root "https://blog.tecosaur.com/tmio/")
|
||||
(require 's) ; Needed for my config
|
||||
|
||||
(let ((css-src (expand-file-name "misc/org-css/main.css" doom-private-dir))
|
||||
(css-dest (expand-file-name "assets/org-style.css" (file-name-directory load-file-name)))
|
||||
(js-src (expand-file-name "misc/org-css/main.js" doom-private-dir))
|
||||
(js-dest (expand-file-name "assets/org-style.js" (file-name-directory load-file-name))))
|
||||
(provide 'config-org-behaviour) ; We *don't* want this
|
||||
(require 'config-org-exports)
|
||||
(require 'config-ox-html)
|
||||
(require 'config-ox-latex)
|
||||
(require 'config-ox-ascii)
|
||||
|
||||
(require 'engrave-faces-html)
|
||||
(load (expand-file-name "engraved-theme.el" (file-name-directory load-file-name)))
|
||||
(engrave-faces-use-theme 'doom-opera-light)
|
||||
|
||||
;; For faces
|
||||
(require 'highlight-quoted)
|
||||
(require 'highlight-numbers)
|
||||
(require 'rainbow-delimiters)
|
||||
|
||||
;; Setup
|
||||
|
||||
(setq site-root "https://blog.tecosaur.net/tmio/"
|
||||
publish-root (file-name-directory load-file-name)
|
||||
content-dir (file-name-concat publish-root "content")
|
||||
html-dir (file-name-concat publish-root "html")
|
||||
assets-dir (file-name-concat publish-root "assets")
|
||||
git-publish-branch "html")
|
||||
|
||||
(setq default-directory publish-root)
|
||||
|
||||
(let ((css-src (expand-file-name "misc/org-css/main.css" doom-user-dir))
|
||||
(css-dest (file-name-concat assets-dir "org-style.css"))
|
||||
(js-src (expand-file-name "misc/org-css/main.js" doom-user-dir))
|
||||
(js-dest (file-name-concat assets-dir "org-style.js")))
|
||||
(when (file-newer-than-file-p css-src css-dest)
|
||||
(copy-file css-src css-dest t))
|
||||
(when (file-newer-than-file-p js-src js-dest)
|
||||
|
@ -48,12 +122,17 @@
|
|||
:width "464"
|
||||
:height "512"
|
||||
:alt "Org unicorn logo")
|
||||
org-export-with-broken-links t
|
||||
org-id-locations-file (expand-file-name ".orgids")
|
||||
org-babel-default-inline-header-args '((:eval . "no") (:exports . "code")))
|
||||
org-babel-default-inline-header-args '((:eval . "no") (:exports . "code"))
|
||||
org-confirm-babel-evaluate nil
|
||||
org-resource-download-policy t
|
||||
user-full-name "TEC"
|
||||
user-mail-address "contact.tmio@tecosaur.net")
|
||||
|
||||
;;; For some reason emoji detection doesn't seem to work, so let's just turn it on
|
||||
|
||||
(setcar (rassoc 'emoji org-latex-conditional-features) t)
|
||||
;; (setcar (rassoc 'emoji org-latex-conditional-features) t)
|
||||
|
||||
;;; Remove generated .tex/.pdf files from the base directory
|
||||
|
||||
|
@ -136,7 +215,7 @@ Return output file name."
|
|||
|
||||
;;; Htmlized file publishing
|
||||
|
||||
(defun org-publish-to-htmlized (_plist filename pub-dir)
|
||||
(defun org-publish-to-engraved (_plist filename pub-dir)
|
||||
"Publish a file with no change other than maybe optimisation.
|
||||
|
||||
FILENAME is the filename of the Org file to be published. PLIST
|
||||
|
@ -146,7 +225,7 @@ publishing directory.
|
|||
Return output file name."
|
||||
(unless (file-directory-p pub-dir)
|
||||
(make-directory pub-dir t))
|
||||
(call-process (expand-file-name "./htmlize-file.el") nil nil nil filename (expand-file-name (concat (file-name-base filename) ".org.html") pub-dir)))
|
||||
(engrave-faces-html-file filename (expand-file-name (concat (file-name-base filename) ".org.html") pub-dir)))
|
||||
|
||||
;;; RSS
|
||||
|
||||
|
@ -176,6 +255,7 @@ PROJECT is the current project."
|
|||
(date (format-time-string "%Y-%m-%d" (org-publish-find-date entry project)))
|
||||
(link (concat (file-name-sans-extension entry) ".html")))
|
||||
(with-temp-buffer
|
||||
(org-mode)
|
||||
(insert (format "* [[file:%s][%s]]\n" file title))
|
||||
(org-set-property "RSS_TITLE" title)
|
||||
(org-set-property "RSS_PERMALINK" link)
|
||||
|
@ -233,17 +313,18 @@ PROJECT is the current project."
|
|||
"This Month in Org - Assets"
|
||||
"This Month in Org - RSS"))
|
||||
("This Month in Org - Pages"
|
||||
:base-directory "./content"
|
||||
:base-directory ,content-dir
|
||||
:base-extension "org"
|
||||
:publishing-directory "./html"
|
||||
:publishing-directory ,html-dir
|
||||
:exclude "rss\\.org"
|
||||
:recursive t
|
||||
:publishing-function
|
||||
(org-html-publish-to-html
|
||||
org-org-publish-to-org
|
||||
org-publish-to-htmlized
|
||||
org-publish-to-engraved
|
||||
org-ascii-publish-to-utf8
|
||||
org-latex-publish-to-pdf)
|
||||
;; org-latex-publish-to-pdf
|
||||
)
|
||||
:headline-levels 4
|
||||
:section-numbers nil
|
||||
:with-toc nil
|
||||
|
@ -252,9 +333,9 @@ PROJECT is the current project."
|
|||
:html-postamble t
|
||||
:html-postamble-format (("en" ,html-postamble)))
|
||||
("This Month in Org - Index"
|
||||
:base-directory "./assets"
|
||||
:base-directory ,assets-dir
|
||||
:base-extension "org"
|
||||
:publishing-directory "./html"
|
||||
:publishing-directory ,html-dir
|
||||
:exclude ".*"
|
||||
:include ("index.org")
|
||||
:recursive nil
|
||||
|
@ -262,14 +343,14 @@ PROJECT is the current project."
|
|||
:headline-levels 4
|
||||
:section-numbers nil
|
||||
:with-toc nil
|
||||
:html-head-extra ,(file-contents "assets/index-head-extra.html")
|
||||
:html-head-extra ,(file-contents (file-name-concat assets-dir "index-head-extra.html"))
|
||||
:html-preamble nil
|
||||
:html-postamble t
|
||||
:html-postamble-format (("en" ,html-postamble)))
|
||||
("This Month in Org - Archive,404"
|
||||
:base-directory "./assets"
|
||||
:base-directory ,assets-dir
|
||||
:base-extension "org"
|
||||
:publishing-directory "./html"
|
||||
:publishing-directory ,html-dir
|
||||
:exclude ".*"
|
||||
:include ("archive.org" "404.org")
|
||||
:recursive nil
|
||||
|
@ -282,19 +363,19 @@ PROJECT is the current project."
|
|||
:html-postamble t
|
||||
:html-postamble-format (("en" ,html-postamble)))
|
||||
("This Month in Org - Assets"
|
||||
:base-directory "./assets"
|
||||
:base-directory ,assets-dir
|
||||
:base-extension any
|
||||
:exclude "\\.html$" ; template files
|
||||
:publishing-directory "./html"
|
||||
:publishing-directory ,html-dir
|
||||
:recursive t
|
||||
:publishing-function org-publish-attachment-optimised)
|
||||
("This Month in Org - RSS"
|
||||
:base-directory "./content"
|
||||
:base-directory ,content-dir
|
||||
:base-extension "org"
|
||||
:recursive nil
|
||||
:exclude ,(rx (or "rss.org" (regexp "DRAFT.*\\.org")))
|
||||
:publishing-function org-rss-publish-to-rss-only
|
||||
:publishing-directory "./html"
|
||||
:publishing-directory ,html-dir
|
||||
:rss-extension "xml"
|
||||
:html-link-home ,site-root
|
||||
:html-link-use-abs-url t
|
||||
|
@ -309,21 +390,110 @@ PROJECT is the current project."
|
|||
))
|
||||
|
||||
(section! "Publishing files")
|
||||
|
||||
(when force
|
||||
(warn! "Force flag set"))
|
||||
|
||||
(when force
|
||||
(delete-directory "./html" t))
|
||||
(when (and force (file-directory-p html-dir))
|
||||
(call-process "git" nil nil nil "worktree" "remove" "-f" git-publish-branch)
|
||||
(call-process "git" nil nil nil "worktree" "prune")
|
||||
(delete-directory html-dir t)
|
||||
(call-process "git" nil nil nil "worktree" "add" html-dir git-publish-branch)
|
||||
(if (file-directory-p html-dir)
|
||||
(dolist (child (directory-files html-dir))
|
||||
(unless (member child '("." ".." ".git"))
|
||||
(if (file-directory-p child)
|
||||
(delete-directory child t)
|
||||
(delete-file child))))
|
||||
(warn! "Failed to create html worktree")))
|
||||
|
||||
(unless (file-directory-p html-dir)
|
||||
(call-process "git" nil nil nil "worktree" "add" html-dir git-publish-branch)
|
||||
(unless (file-directory-p html-dir)
|
||||
(warn! "Failed to create html worktree")))
|
||||
|
||||
(org-publish "This Month in Org" force)
|
||||
|
||||
(section! "Uploading")
|
||||
(let ((rsync-status
|
||||
(with-temp-buffer
|
||||
(cons (call-process "rsync" nil t nil "-avzL" "--delete"
|
||||
(expand-file-name "html/" (file-name-directory load-file-name))
|
||||
"imh:/home/thedia18/public_html/tecosaur.com/blog/tmio/")
|
||||
(message "\033[0;33m%s\033[0m" (buffer-string))))))
|
||||
(if (= (car rsync-status) 0)
|
||||
(success! "Content uploaded")
|
||||
(error! "Content failed to upload, rsync exited with code %d" rsync-code)))
|
||||
(section! "Pushing")
|
||||
|
||||
;; To make somewhat nice git history in the HTML branch, we'll want to collect
|
||||
;; information on the current state off affairs and commit accordingly.
|
||||
;;
|
||||
;; We start by checking to see if we should make a "publish" style commit or a
|
||||
;; "draft" style commit. This is determied by seeing if there are any
|
||||
;; =content/...= lines in the git status, the assumption being that at each
|
||||
;; publish point everything under =content/= has been comitted.
|
||||
;;
|
||||
;; Then we check to see if the last commit in the html branch is a "publish"
|
||||
;; style commit or a "draft" style commit. We make this easy for ourselves by
|
||||
;; prepending draft commits messages with the keyword "DRAFT". Should the last
|
||||
;; commit be a draft, we replace it. Otherwise, a new commit is created.
|
||||
;;
|
||||
;; Lastly, we actually push the HTML branch.
|
||||
|
||||
(defun last-commit-log (fmt &optional branch)
|
||||
"Get the log line for the last commit in FMT (optionally for BRANCH)."
|
||||
(with-temp-buffer
|
||||
(apply #'call-process "git" nil t nil "log"
|
||||
(delq nil (list (and branch (format "refs/heads/%s" branch)) "-1"
|
||||
(format "--pretty=format:%s" fmt))))
|
||||
(buffer-string)))
|
||||
|
||||
(defun last-commit-subject (&optional branch)
|
||||
"Get the commit subject line."
|
||||
(last-commit-log "%s" branch))
|
||||
|
||||
(defun last-commit-hash (&optional branch)
|
||||
"Get the commit subject line."
|
||||
(last-commit-log "%h" branch))
|
||||
|
||||
(defun get-unstaged-changes ()
|
||||
(with-temp-buffer
|
||||
(call-process "git" nil t nil "status" "--porcelain=v1")
|
||||
(goto-char (point-min))
|
||||
(let (changes)
|
||||
(while (re-search-forward "^\\(..\\) +" nil t)
|
||||
(push (cons (match-string 1)
|
||||
(and (re-search-forward "[^\n]+" nil t)
|
||||
(match-string 0)))
|
||||
changes))
|
||||
changes)))
|
||||
|
||||
(defun git-try-command (&rest args)
|
||||
(with-temp-buffer
|
||||
(setq args (delq nil args))
|
||||
(let ((exit-code (apply #'call-process "git" nil t nil args)))
|
||||
(or (eq exit-code 0)
|
||||
(progn
|
||||
(error! "Failed to %s" (car args))
|
||||
(message " Git command: git %s" (mapconcat #'shell-quote-argument args " "))
|
||||
(message " Error: %s" (mapconcat #'identity (split-string (buffer-string) "\n") "\n "))
|
||||
nil)))))
|
||||
|
||||
(let* ((source-draft-p (and (or update-draft (not update-commit))
|
||||
(member (file-name-base content-dir)
|
||||
(mapcar
|
||||
(lambda (change) (car (file-name-split (cdr change))))
|
||||
(get-unstaged-changes)))))
|
||||
(html-draft-p (string-prefix-p "DRAFT " (last-commit-subject git-publish-branch)))
|
||||
(html-changed-files (length (let ((default-directory html-dir)) (get-unstaged-changes))))
|
||||
(commit-message
|
||||
(if source-draft-p
|
||||
(format "DRAFT update (%s files changed)\nLast source commit: %s\nLocal time: %s"
|
||||
html-changed-files
|
||||
(last-commit-hash)
|
||||
(format-time-string "%F %T (UTC%z)"))
|
||||
(format "Publish update based on %s" (last-commit-hash)))))
|
||||
(if (= html-changed-files 0)
|
||||
(warn! "No changes to push")
|
||||
(let ((default-directory html-dir))
|
||||
(unless source-draft-p
|
||||
(dolist (file (mapcar #'cdr (get-unstaged-changes)))
|
||||
(when (and (file-exists-p file)
|
||||
(string-prefix-p "DRAFT-" (file-name-base file)))
|
||||
(delete-file file))))
|
||||
(and (git-try-command "add" "-A")
|
||||
(git-try-command "commit" (and html-draft-p "--amend") "--message" commit-message)
|
||||
(git-try-command "push" (and html-draft-p "--force-with-lease"))))))
|
||||
|
||||
(section! "Finished")
|
||||
|
|
Loading…
Reference in New Issue