247 lines
24 KiB
Plaintext
247 lines
24 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="Artyom Bologov" />
|
||
<title>Writing Nyxt Extensions: Example of nx-search-engines</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">Writing Nyxt Extensions: Example of nx-search-engines</h1>
|
||
<p class="author">Artyom Bologov</p>
|
||
</header>
|
||
<p>Nyxt is an extensible browser. But how does one write an extension for it? Given that there are few extensions (as of March 2021), there isn't much existing code to learn from. That's why I've written this step-by-step guide about how to extend Nyxt.</p>
|
||
<p>So, here's the process you can follow:</p>
|
||
<h1 id="create-a-cl-package-and-an-asdf-system.">Create a CL package and an ASDF system.</h1>
|
||
<p>Nyxt is built in Common Lisp, so you need to follow the packaging conventions for Common Lisp programs:</p>
|
||
<ul>
|
||
<li>Create a separate package in a separate repository.
|
||
<ul>
|
||
<li>Write a package.lisp file with your package definitions.</li>
|
||
</ul></li>
|
||
<li>Write a system/systems definition relying on <a href="https://www.common-lisp.net/project/asdf/asdf.html">ASDF</a>.</li>
|
||
<li>(Nyxt-specific recommendation) Name the repository and system with a <code>nx-</code> prefix for discoverability.</li>
|
||
</ul>
|
||
<p>It's a lot, isn't it? Fortunately, all these routines can be automated with <code>quickproject</code>. So, you can open up Lisp REPL and do:</p>
|
||
<div class="sourceCode" id="cb1" data-org-language="lisp"><pre class="sourceCode commonlisp"><code class="sourceCode commonlisp"><a class="sourceLine" id="cb1-1" data-line-number="1">(ql:quickload :quickproject) <span class="co">;; Load quickproject</span></a>
|
||
<a class="sourceLine" id="cb1-2" data-line-number="2"><span class="co">;; Create all the necessary things.</span></a>
|
||
<a class="sourceLine" id="cb1-3" data-line-number="3"><span class="co">;; In my case, I ran something like:</span></a>
|
||
<a class="sourceLine" id="cb1-4" data-line-number="4">(quickproject:make-project</a>
|
||
<a class="sourceLine" id="cb1-5" data-line-number="5"> <span class="co">;; Path to your extension. Remember the nx- prefix :)</span></a>
|
||
<a class="sourceLine" id="cb1-6" data-line-number="6"> <span class="st">"~/git/nx-search-engines/"</span></a>
|
||
<a class="sourceLine" id="cb1-7" data-line-number="7"> <span class="co">;; Your name.</span></a>
|
||
<a class="sourceLine" id="cb1-8" data-line-number="8"> :author <span class="st">"Artyom Bologov"</span></a>
|
||
<a class="sourceLine" id="cb1-9" data-line-number="9"> <span class="co">;; The license you want to distribute it under.</span></a>
|
||
<a class="sourceLine" id="cb1-10" data-line-number="10"> :license <span class="st">"BSD 2-clause"</span></a>
|
||
<a class="sourceLine" id="cb1-11" data-line-number="11"> <span class="co">;; You depend on Nyxt -- you're writing an extension for it, after all.</span></a>
|
||
<a class="sourceLine" id="cb1-12" data-line-number="12"> :depends-on '(:nyxt))</a></code></pre></div>
|
||
<p>And most of the work will be done for you!</p>
|
||
<h1 id="set-up-your-package">Set-up your package</h1>
|
||
<p>You'll likely need to refer to Nyxt symbols (be they names of functions, classes, or variables). Typically this can be done by using the <code>nyxt:</code> prefix. To avoid that, you can import the frequently used symbols from the <code>nyxt</code> package. In the case of <code>nx-search-engines</code>, I needed <code>define-class</code>, <code>define-mode</code>, <code>define-command</code>, and <code>search-engine</code> class.</p>
|
||
<p>Importing can be done via the <a href="http://www.lispworks.com/documentation/HyperSpec/Body/m_defpkg.htm">package definition</a>, together with nickname setting, symbol exporting, and package documentation. In the case of <code>nx-search-engines</code>, package definition looked like this:</p>
|
||
<div class="sourceCode" id="cb2" data-org-language="lisp"><pre class="sourceCode commonlisp"><code class="sourceCode commonlisp"><a class="sourceLine" id="cb2-1" data-line-number="1"><span class="co">;;;; package.lisp</span></a>
|
||
<a class="sourceLine" id="cb2-2" data-line-number="2"></a>
|
||
<a class="sourceLine" id="cb2-3" data-line-number="3">(<span class="kw">defpackage</span><span class="fu"> </span>#:nx-search-engines</a>
|
||
<a class="sourceLine" id="cb2-4" data-line-number="4"> <span class="co">;; "Systematically importing all symbols with `:use #:nyxt` is</span></a>
|
||
<a class="sourceLine" id="cb2-5" data-line-number="5"> <span class="co">;; discouraged because it exposes your package to collisions upon</span></a>
|
||
<a class="sourceLine" id="cb2-6" data-line-number="6"> <span class="co">;; API changes when `nyxt` gets updated."</span></a>
|
||
<a class="sourceLine" id="cb2-7" data-line-number="7"> (<span class="bu">:use</span> #:cl)</a>
|
||
<a class="sourceLine" id="cb2-8" data-line-number="8"> <span class="co">;; Symbols I don't want to prefix.</span></a>
|
||
<a class="sourceLine" id="cb2-9" data-line-number="9"> (:import-from #:nyxt</a>
|
||
<a class="sourceLine" id="cb2-10" data-line-number="10"> #:define-class</a>
|
||
<a class="sourceLine" id="cb2-11" data-line-number="11"> #:define-mode</a>
|
||
<a class="sourceLine" id="cb2-12" data-line-number="12"> #:define-command</a>
|
||
<a class="sourceLine" id="cb2-13" data-line-number="13"> #:search-engine)</a>
|
||
<a class="sourceLine" id="cb2-14" data-line-number="14"> <span class="co">;; Symbols I want to be exported from nx-search-engines.</span></a>
|
||
<a class="sourceLine" id="cb2-15" data-line-number="15"> <span class="co">;; This is a traditional and not-so-flexible way to export things.</span></a>
|
||
<a class="sourceLine" id="cb2-16" data-line-number="16"> <span class="co">;; To export symbols from the extension files, use `serapeum:export-always'.</span></a>
|
||
<a class="sourceLine" id="cb2-17" data-line-number="17"> (:export #:duckduckgo</a>
|
||
<a class="sourceLine" id="cb2-18" data-line-number="18"> #:duckduckgo-images</a>
|
||
<a class="sourceLine" id="cb2-19" data-line-number="19"> #:google</a>
|
||
<a class="sourceLine" id="cb2-20" data-line-number="20"> #:google-images</a>
|
||
<a class="sourceLine" id="cb2-21" data-line-number="21"> #:bing-date</a>
|
||
<a class="sourceLine" id="cb2-22" data-line-number="22"> #:bing</a>
|
||
<a class="sourceLine" id="cb2-23" data-line-number="23"> #:bing-images</a>
|
||
<a class="sourceLine" id="cb2-24" data-line-number="24"> #:bing-videos</a>
|
||
<a class="sourceLine" id="cb2-25" data-line-number="25"> #:bing-maps</a>
|
||
<a class="sourceLine" id="cb2-26" data-line-number="26"> #:bing-news</a>
|
||
<a class="sourceLine" id="cb2-27" data-line-number="27"> #:bing-shopping</a>
|
||
<a class="sourceLine" id="cb2-28" data-line-number="28"> #:wordnet)</a>
|
||
<a class="sourceLine" id="cb2-29" data-line-number="29"> (:documentation <span class="st">"A collection of search engines for Nyxt browser."</span>))</a></code></pre></div>
|
||
<h1 id="write-the-code">Write the code</h1>
|
||
<p>If you know Common Lisp, this step is straightforward – just write the extension relying on numerous Nyxt APIs (see next section about them).</p>
|
||
<p>If you don't know Lisp – no problem, you can always learn it and write a great extension in the process! We've put together a collection of resources that can help you in starting out: <a href="https://nyxt.atlas.engineer/learn-lisp">Nyxt Common Lisp Learning Recommendations</a>.</p>
|
||
<h1 id="use-nyxt-apis">Use Nyxt APIs</h1>
|
||
<p>There are lots of libraries Nyxt depends on. You can freely use them. Nyxt will guarantee that they are loaded. A non-exhaustive list of libraries you can rely on:</p>
|
||
<ul>
|
||
<li><a href="https://common-lisp.net/project/alexandria/">Alexandria</a> – a battle-tested utilities library.</li>
|
||
<li><a href="https://github.com/ruricolist/serapeum">Serapeum</a> – a bigger and frequently updated set of utilities.</li>
|
||
<li><a href="https://common-lisp.net/project/bordeaux-threads/">Bordeaux Threads</a> – a simple multithreading primitives library.
|
||
<ul>
|
||
<li><a href="https://github.com/hawkir/calispel">Calispel</a> builds a great concurrency layer on top of Bordeaux Threads.</li>
|
||
</ul></li>
|
||
<li><a href="https://edicl.github.io/cl-ppcre/">CL-PPCRE</a> – a fast and Perl-compliant regular expressions library.
|
||
<ul>
|
||
<li><a href="https://github.com/vindarel/cl-str">str</a> – an intuitive string-manipulation library. Relies on CL-PPCRE.</li>
|
||
</ul></li>
|
||
<li><a href="https://github.com/fukamachi/quri">QURI</a> – a standard-compliant and fast URL representation. We use it in Nyxt core and it's much more reliable than using strings for URL storage.</li>
|
||
<li><a href="https://common-lisp.net/project/local-time/">Local-time</a> to manage dates and times.</li>
|
||
<li><a href="https://github.com/arielnetworks/cl-markup">CL-MARKUP</a>, <a href="https://github.com/Inaimathi/cl-css">CL-CSS</a>, <a href="https://common-lisp.net/project/parenscript/">Parenscript</a>, <a href="https://common-lisp.net/project/cl-json/cl-json.html">CL-JSON</a> to generate (respectively) HTML, CSS, JavaScript, and read JSON without leaving Lisp land.</li>
|
||
<li><a href="https://shinmera.github.io/plump/">Plump</a> as a performant and error-resistant HTML parser.</li>
|
||
<li><a href="https://github.com/pcostanza/closer-mop">Closer MOP</a> and <a href="https://github.com/gwkkwg/moptilities">Moptilities</a> as convenient Metaobject Protocol libraries to query and modify your classes at runtime.</li>
|
||
<li><a href="https://github.com/guicho271828/trivia">Trivia</a> for powerful pattern-matching.</li>
|
||
</ul>
|
||
<p>Nyxt APIs rely on the above libraries and allow you to shorten your code and extend Nyxt in a wink:</p>
|
||
<ul>
|
||
<li><a href="https://nyxt.atlas.engineer/article/autofills.org">Autofills</a> as a way to define user-callable text generation of arbitrary complexity.</li>
|
||
<li><a href="https://nyxt.atlas.engineer/article/auto-mode.org">Auto-mode</a> and its <code>add-modes-to-auto-mode-rules</code> to associate modes with URLs that they need to be automagically enabled on.</li>
|
||
<li><code>define-class</code>, <code>define-user-class</code>, and <code>define-configuration</code> as ways to make your extension as easily extensible <a href="https://nyxt.atlas.engineer/article/class-based-functional-configuration.org">as the Nyxt core is</a>.</li>
|
||
<li>Data storage API. You can thread-safely use arbitrary <code>nyxt:data-path</code>-persisted data using <code>with-data-access</code> and query it unsafely with <code>with-data-unsafe</code>.</li>
|
||
<li><a href="https://nyxt.atlas.engineer/article/element-hints.org">Element hints</a> classes and <code>query-hints</code> for keyboard-only navigation.</li>
|
||
<li>Fuzzy-matching and <code>prompt-buffer</code> with the over-powered <code>prompt</code>. Just use it with suitable <code>source</code>-s and enjoy :)</li>
|
||
<li><a href="https://nyxt.atlas.engineer/article/global-history-tree.org">Global History Tree</a> – a lossless tree-like history mechanism. The underlying data structure can be used outside the domain of history management, e.g., in filesystem tracking or in smart, tree-reliant commands like Emacs' ones.</li>
|
||
<li><a href="https://nyxt.atlas.engineer/article/hooks.org">Hooks</a> that have a great <a href="https://nyxt.atlas.engineer/article/hooks-implementation.org">type support and are easy to compose</a>.</li>
|
||
<li>Password Interface, extensible access for your password manager of choice and callable from the Lisp code.</li>
|
||
<li>Lots of <code>nyxt/web-mode</code> commands managing web navigation, be it history or page movement.</li>
|
||
<li>Data Analysis library <a href="https://nyxt.atlas.engineer/article/dbscan.org">suitable</a> for your own small-scale data crunching.</li>
|
||
<li><a href="https://nyxt.atlas.engineer/article/package-manager.org">OS Package Manager</a> to query the system package manager and install necessary utilitie.</li>
|
||
<li><code>user-interface</code> library to build your Lisp-powered extension interfaces from.</li>
|
||
</ul>
|
||
<p>Since we use the Common Lisp package system, you can guess the stability of the API by how it's used:</p>
|
||
<ul>
|
||
<li>If it's exported and you can easily use it by prefixing it with <code>nyxt:</code>, then it's relatively stable and intended for extension use.</li>
|
||
<li>If it's not exported (usable only with <code>nyxt::</code> prefix), then it may disappear someday.</li>
|
||
<li>If it's not exported and has a percent sign in its name (e.g., <code>nyxt::%buffer</code>) – do not use it. It's an implementation detail that can change anytime and is intended for Nyxt-internal use.</li>
|
||
</ul>
|
||
<p>However, as it's all written in Lisp, no one restricts you from using anything you can get your hands on ;)</p>
|
||
<h2 id="nx-search-engines-example">nx-search-engines example</h2>
|
||
<p>In the case of <code>nx-search-engines</code>, I relied on the <code>search-engine</code> class – after all, I needed to generate Nyxt-native search engines. This is quite a simple and boring API, and yet it's sufficient to allow Lisp-customizable search engines.</p>
|
||
<p>Another Nyxt API that I relied upon (particularly in <code>search-engines-mode</code>) was element hints. The <code>search-hint</code> command is a <code>follow-hint</code> sibling. The difference is that it searches the class-dispatchable hints instead of following them. All at the cost of several method definitions and a <code>search-hint</code> command call! That's how it looks:</p>
|
||
<div class="sourceCode" id="cb3" data-org-language="lisp"><pre class="sourceCode commonlisp"><code class="sourceCode commonlisp"><a class="sourceLine" id="cb3-1" data-line-number="1"><span class="co">;; One of the methods that search an element hint's contents.</span></a>
|
||
<a class="sourceLine" id="cb3-2" data-line-number="2"><span class="co">;; This one uses the user-settable `image-search-engine' to search image URL.</span></a>
|
||
<a class="sourceLine" id="cb3-3" data-line-number="3">(<span class="kw">defmethod</span><span class="fu"> </span>%search-hint ((hint nyxt/web-mode::image-hint))</a>
|
||
<a class="sourceLine" id="cb3-4" data-line-number="4"> (nyxt:buffer-load (nyxt::generate-search-query</a>
|
||
<a class="sourceLine" id="cb3-5" data-line-number="5"> (nyxt/web-mode::url hint)</a>
|
||
<a class="sourceLine" id="cb3-6" data-line-number="6"> (nyxt:search-url (image-search-engine</a>
|
||
<a class="sourceLine" id="cb3-7" data-line-number="7"> (nyxt:find-submode (nyxt:current-buffer)</a>
|
||
<a class="sourceLine" id="cb3-8" data-line-number="8"> 'nyxt::search-engines-mode))))))</a>
|
||
<a class="sourceLine" id="cb3-9" data-line-number="9"><span class="co">;;; More `%search-hint' definitions...</span></a>
|
||
<a class="sourceLine" id="cb3-10" data-line-number="10"></a>
|
||
<a class="sourceLine" id="cb3-11" data-line-number="11">(define-command search-hint (&key annotate-visible-only-p)</a>
|
||
<a class="sourceLine" id="cb3-12" data-line-number="12"> <span class="st">"Search for the contents of the hint with default search engines.</span></a>
|
||
<a class="sourceLine" id="cb3-13" data-line-number="13"><span class="st">In the case of links and input areas, a default search engine of Nyxt is</span></a>
|
||
<a class="sourceLine" id="cb3-14" data-line-number="14"><span class="st">used (unless overridden by `engines:search-engine').</span></a>
|
||
<a class="sourceLine" id="cb3-15" data-line-number="15"><span class="st">In case of images, `engines:image-search-engine' is used."</span></a>
|
||
<a class="sourceLine" id="cb3-16" data-line-number="16"> (nyxt/web-mode::query-hints <span class="st">"Search element"</span> '%search-hint</a>
|
||
<a class="sourceLine" id="cb3-17" data-line-number="17"> :annotate-visible-only-p annotate-visible-only-p))</a></code></pre></div>
|
||
<h1 id="make-the-extension-extensible">Make the extension extensible :)</h1>
|
||
<p>Nyxt uses the <a href="https://lispcookbook.github.io/cl-cookbook/clos.html">Common Lisp Object System (CLOS)</a> for everything. There are Nyxt-specific macros to make any CLOS class configurable by the user. To make your extension customizable, you need to know only two of them: <code>define-user-class</code> and <code>define-mode</code>.</p>
|
||
<p><code>define-user-class</code> makes a class you've already defined (with <code>defclass</code> or <code>define-class</code>) configurable via <code>define-configuration</code>. That's the only thing you need to write to make your classes customizable:</p>
|
||
<div class="sourceCode" id="cb4" data-org-language="lisp"><pre class="sourceCode commonlisp"><code class="sourceCode commonlisp"><a class="sourceLine" id="cb4-1" data-line-number="1"><span class="co">;; Define your class. `define-class' is used for brevity.</span></a>
|
||
<a class="sourceLine" id="cb4-2" data-line-number="2">(define-class your-class ()</a>
|
||
<a class="sourceLine" id="cb4-3" data-line-number="3"> ((slot-name <span class="kw">nil</span></a>
|
||
<a class="sourceLine" id="cb4-4" data-line-number="4"> <span class="bu">:type</span> (<span class="kw">or</span> <span class="kw">integer</span> <span class="kw">nil</span>)</a>
|
||
<a class="sourceLine" id="cb4-5" data-line-number="5"> :documentation <span class="st">"Example slot."</span>))</a>
|
||
<a class="sourceLine" id="cb4-6" data-line-number="6"> (:export-class-name-p <span class="kw">t</span>) <span class="co">; Your class name will be exported with your package prefix.</span></a>
|
||
<a class="sourceLine" id="cb4-7" data-line-number="7"> (:export-accessor-names-p <span class="kw">t</span>) <span class="co">; Slot names will be exported too.</span></a>
|
||
<a class="sourceLine" id="cb4-8" data-line-number="8"> (:export-predicate-name-p <span class="kw">t</span>) <span class="co">; A your-class-p type-checking predicate will be exported.</span></a>
|
||
<a class="sourceLine" id="cb4-9" data-line-number="9"> (:accessor-name-transformer (hu.dwim.defclass-star:make-name-transformer name)))</a>
|
||
<a class="sourceLine" id="cb4-10" data-line-number="10"></a>
|
||
<a class="sourceLine" id="cb4-11" data-line-number="11">(define-user-class your-class)</a></code></pre></div>
|
||
<p><code>define-mode</code> relies on this same system with <code>define-class</code>, <code>define-user-class</code>, and <code>define-configuration</code>. The difference is that modes are enableable and user-facing, while other classes usually aren't. A mode is the best place to store your extensions' configuration. I've relied on this with <code>nx-search-engines</code> and defined <code>search-engines-mode</code>:</p>
|
||
<div class="sourceCode" id="cb5" data-org-language="lisp"><pre class="sourceCode commonlisp"><code class="sourceCode commonlisp"><a class="sourceLine" id="cb5-1" data-line-number="1">(define-mode search-engines-mode ()</a>
|
||
<a class="sourceLine" id="cb5-2" data-line-number="2"> <span class="st">"A mode to search hints in the dedicated search engine and image search engine."</span></a>
|
||
<a class="sourceLine" id="cb5-3" data-line-number="3"> ((search-engine (nyxt::default-search-engine</a>
|
||
<a class="sourceLine" id="cb5-4" data-line-number="4"> (nyxt:search-engines (nyxt:current-buffer)))</a>
|
||
<a class="sourceLine" id="cb5-5" data-line-number="5"> <span class="bu">:type</span> (<span class="kw">or</span> nyxt:search-engine <span class="kw">null</span>)</a>
|
||
<a class="sourceLine" id="cb5-6" data-line-number="6"> :documentation <span class="st">"The search engine to use when calling `search-hint'."</span>)</a>
|
||
<a class="sourceLine" id="cb5-7" data-line-number="7"> (image-search-engine (google-images)</a>
|
||
<a class="sourceLine" id="cb5-8" data-line-number="8"> <span class="bu">:type</span> (<span class="kw">or</span> nyxt:search-engine <span class="kw">null</span>)</a>
|
||
<a class="sourceLine" id="cb5-9" data-line-number="9"> :documentation <span class="st">"The search engine to use when calling `search-hint' on images."</span>)))</a></code></pre></div>
|
||
<p>Search is the only thing <code>nx-search-engines</code> is concerned about. Customization of search engines to use when searching element hints is the only reasonable configuration there.</p>
|
||
<p>Now one can change preferred search engines like this:</p>
|
||
<div class="sourceCode" id="cb6" data-org-language="lisp"><pre class="sourceCode commonlisp"><code class="sourceCode commonlisp"><a class="sourceLine" id="cb6-1" data-line-number="1">(define-configuration engines:search-engines-mode</a>
|
||
<a class="sourceLine" id="cb6-2" data-line-number="2"> ((engines:search-engine (engines:duckduckgo))</a>
|
||
<a class="sourceLine" id="cb6-3" data-line-number="3"> (engines:image-search-engine (engines:duckduckgo-images))))</a></code></pre></div>
|
||
<h1 id="make-nyxt-users-happy-by-publishing-the-extension">Make Nyxt users happy by publishing the extension!</h1>
|
||
<p>Now that you've written your extension, packaged it, and used all the necessary customizable APIs, you can share it with the world! Don't forget to <a href="https://github.com/atlas-engineer/nyxt/pulls">let us know</a> about your extension for it to be included in a <a href="https://github.com/atlas-engineer/nyxt/blob/master/documents/EXTENSIONS.org">list of Nyxt extensions</a>.</p>
|
||
<p>Thanks for reading :3</p>
|
||
</body>
|
||
</html>
|