emacs/var/elfeed/db/data/8b/8bb5c6f54e9d4bd9d862711bf88f751625ea4470
2022-01-03 12:49:32 -06:00

155 lines
12 KiB
Plaintext

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<meta name="author" content="By John Mercouris" />
<title>Command Line Programs</title>
<style type="text/css">
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
</style>
<style type="text/css">
a.sourceLine { display: inline-block; line-height: 1.25; }
a.sourceLine { pointer-events: none; color: inherit; text-decoration: inherit; }
a.sourceLine:empty { height: 1.2em; position: absolute; }
.sourceCode { overflow: visible; }
code.sourceCode { white-space: pre; position: relative; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
code.sourceCode { white-space: pre-wrap; }
a.sourceLine { text-indent: -1em; padding-left: 1em; }
}
pre.numberSource a.sourceLine
{ position: relative; }
pre.numberSource a.sourceLine:empty
{ position: absolute; }
pre.numberSource a.sourceLine::before
{ content: attr(data-line-number);
position: absolute; left: -5em; text-align: right; vertical-align: baseline;
border: none; pointer-events: all;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
a.sourceLine::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */
code span.bu { } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
code span.dt { color: #902000; } /* DataType */
code span.dv { color: #40a070; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */
code span.ot { color: #007020; } /* Other */
code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { color: #4070a0; } /* String */
code span.va { color: #19177c; } /* Variable */
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
</style>
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
<![endif]-->
</head>
<body>
<header>
<h1 class="title">Command Line Programs</h1>
<p class="author">By John Mercouris</p>
</header>
<h1 id="running-programs-in-nyxt">Running Programs in Nyxt</h1>
<p>Nyxt gives you the power to extend its capabilities by invoking other programs. This allows you to chain Lisp functions and operations with any programs of your choosing.</p>
<h1 id="a-practical-example-download-youtube-videos">A Practical Example: Download Youtube Videos</h1>
<p>Let's consider the following situation: you are watching a Youtube video, but wait! You have somewhere to be! Why not download the video so you can watch it on the train where your internet access will be limited? Sounds good right? Let's see what options there are.</p>
<p>A quick search on the internet reveals a very convenient program called <a href="https://github.com/rg3/youtube-dl/">youtube-dl</a>. Youtube-dl is invoked via the command line like this: <code>youtube-dl &quot;url-to-download&quot;</code>. Of course there are other flags and arguments, but let's consider the simplest case.</p>
<p>You could simply copy the URL and paste it into the terminal. That's not really cool though. Let's automate it:</p>
<div class="sourceCode" id="youtube-dl" data-org-language="lisp"><pre class="sourceCode commonlisp"><code class="sourceCode commonlisp"><a class="sourceLine" id="youtube-dl-1" data-line-number="1">(define-command youtube-dl-current-page ()</a>
<a class="sourceLine" id="youtube-dl-2" data-line-number="2"> <span class="st">&quot;Download a Youtube video in the currently open buffer.&quot;</span></a>
<a class="sourceLine" id="youtube-dl-3" data-line-number="3"> (with-result (url (buffer-get-url))</a>
<a class="sourceLine" id="youtube-dl-4" data-line-number="4"> (uiop:run-program</a>
<a class="sourceLine" id="youtube-dl-5" data-line-number="5"> (<span class="kw">list</span> <span class="st">&quot;youtube-dl&quot;</span> url))))</a></code></pre></div>
<p>Just like that! Instant Youtube downloader script. If you want, bind it to a keybinding:</p>
<div class="sourceCode" id="youtube-dl-keybinding" data-org-language="lisp"><pre class="sourceCode commonlisp"><code class="sourceCode commonlisp"><a class="sourceLine" id="youtube-dl-keybinding-1" data-line-number="1">(define-key <span class="st">&quot;C-c d&quot;</span> &#39;youtube-dl-current-page)</a></code></pre></div>
<p>Now whenever you want to download a Youtube video simply &quot;C-c d&quot; and you'll have it on your computer!</p>
<h1 id="shell-mode">&quot;Shell&quot; Mode</h1>
<p>That was cool, but it doesn't really show the true power of Nyxt. An example that is more illustrative is a very basic &quot;shell&quot; implementation. It is not really a shell because it doesn't have variables, piping, or anything else a shell really has, but it can run programs.</p>
<p>Simply put: shell mode is an extension for running simple one-liner shell commands and seeing the output. There is no history or variables. Use <code>C-x s</code> to enter <code>*shell-mode*</code> and <code>c</code> to enter a command and <code>k</code> to clear the command output.</p>
<div class="sourceCode" id="shell-mode" data-org-language="lisp"><pre class="sourceCode commonlisp"><code class="sourceCode commonlisp"><a class="sourceLine" id="shell-mode-1" data-line-number="1">(define-mode shell-mode ()</a>
<a class="sourceLine" id="shell-mode-2" data-line-number="2"> <span class="st">&quot;A basic shell prompt.&quot;</span></a>
<a class="sourceLine" id="shell-mode-3" data-line-number="3"> ((keymap-schemes</a>
<a class="sourceLine" id="shell-mode-4" data-line-number="4"> :initform</a>
<a class="sourceLine" id="shell-mode-5" data-line-number="5"> (<span class="kw">let</span> ((<span class="kw">map</span> (make-keymap)))</a>
<a class="sourceLine" id="shell-mode-6" data-line-number="6"> (define-key :keymap <span class="kw">map</span></a>
<a class="sourceLine" id="shell-mode-7" data-line-number="7"> <span class="st">&quot;c&quot;</span> &#39;run-shell-command</a>
<a class="sourceLine" id="shell-mode-8" data-line-number="8"> <span class="st">&quot;k&quot;</span> &#39;clear-shell)</a>
<a class="sourceLine" id="shell-mode-9" data-line-number="9"> (<span class="kw">list</span> :emacs <span class="kw">map</span></a>
<a class="sourceLine" id="shell-mode-10" data-line-number="10"> :vi-normal <span class="kw">map</span>)))))</a>
<a class="sourceLine" id="shell-mode-11" data-line-number="11"></a>
<a class="sourceLine" id="shell-mode-12" data-line-number="12">(define-parenscript clear-shell-output ()</a>
<a class="sourceLine" id="shell-mode-13" data-line-number="13"> (<span class="kw">setf</span> (ps:chain document body inner-h-t-m-l) <span class="st">&quot;&quot;</span>))</a>
<a class="sourceLine" id="shell-mode-14" data-line-number="14"></a>
<a class="sourceLine" id="shell-mode-15" data-line-number="15">(define-command clear-shell (shell-mode)</a>
<a class="sourceLine" id="shell-mode-16" data-line-number="16"> <span class="st">&quot;Clear the output in the shell buffer.&quot;</span></a>
<a class="sourceLine" id="shell-mode-17" data-line-number="17"> (rpc-buffer-evaluate-javascript</a>
<a class="sourceLine" id="shell-mode-18" data-line-number="18"> *interface* (active-buffer *interface*)</a>
<a class="sourceLine" id="shell-mode-19" data-line-number="19"> (clear-shell-output)))</a>
<a class="sourceLine" id="shell-mode-20" data-line-number="20"></a>
<a class="sourceLine" id="shell-mode-21" data-line-number="21">(define-parenscript append-output (output)</a>
<a class="sourceLine" id="shell-mode-22" data-line-number="22"> (<span class="kw">setf</span> (ps:chain document body inner-h-t-m-l)</a>
<a class="sourceLine" id="shell-mode-23" data-line-number="23"> (ps:chain document body inner-h-t-m-l</a>
<a class="sourceLine" id="shell-mode-24" data-line-number="24"> (concat (ps:lisp</a>
<a class="sourceLine" id="shell-mode-25" data-line-number="25"> (<span class="kw">format</span> <span class="kw">nil</span> <span class="st">&quot;&lt;pre&gt;&lt;code&gt;~a&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;&quot;</span> output))))))</a>
<a class="sourceLine" id="shell-mode-26" data-line-number="26"></a>
<a class="sourceLine" id="shell-mode-27" data-line-number="27">(define-command run-shell-command (shell-mode)</a>
<a class="sourceLine" id="shell-mode-28" data-line-number="28"> <span class="st">&quot;Run a shell command.&quot;</span></a>
<a class="sourceLine" id="shell-mode-29" data-line-number="29"> (with-result</a>
<a class="sourceLine" id="shell-mode-30" data-line-number="30"> (input (read-from-minibuffer</a>
<a class="sourceLine" id="shell-mode-31" data-line-number="31"> (minibuffer *interface*)</a>
<a class="sourceLine" id="shell-mode-32" data-line-number="32"> :input-prompt <span class="st">&quot;Run in shell:&quot;</span>))</a>
<a class="sourceLine" id="shell-mode-33" data-line-number="33"> (rpc-buffer-evaluate-javascript</a>
<a class="sourceLine" id="shell-mode-34" data-line-number="34"> *interface* (active-buffer *interface*)</a>
<a class="sourceLine" id="shell-mode-35" data-line-number="35"> (append-output</a>
<a class="sourceLine" id="shell-mode-36" data-line-number="36"> <span class="bu">:output</span></a>
<a class="sourceLine" id="shell-mode-37" data-line-number="37"> (uiop:run-program input :force-shell <span class="kw">t</span> <span class="bu">:output</span> :string)))))</a>
<a class="sourceLine" id="shell-mode-38" data-line-number="38"></a>
<a class="sourceLine" id="shell-mode-39" data-line-number="39">(define-command shell ()</a>
<a class="sourceLine" id="shell-mode-40" data-line-number="40"> <span class="st">&quot;Open a shell buffer.&quot;</span></a>
<a class="sourceLine" id="shell-mode-41" data-line-number="41"> (set-active-buffer *interface* (make-buffer <span class="bu">:name</span> <span class="st">&quot;*shell*&quot;</span> :default-modes &#39;(shell-mode))))</a>
<a class="sourceLine" id="shell-mode-42" data-line-number="42"></a>
<a class="sourceLine" id="shell-mode-43" data-line-number="43">(define-key <span class="st">&quot;C-x s&quot;</span> #&#39;shell)</a></code></pre></div>
<p>Within 40 lines of Lisp we've managed to make a completely new mode that allows us to execute commands, view the output on screen, and even clear the screen.</p>
<h1 id="the-take-away">The Take Away</h1>
<p>Nyxt can be extended with any program of any type as long as it accepts some form of IPC. This means that you can chain any process you want on your computer. Of course, this application has bounds of reason, you shouldn't imagine that Nyxt will turn into your system shell, process manager- even though it could.</p>
<p>Thanks for reading!</p>
</body>
</html>