A Markdown reader for Gnome (or the browser.)
This is small project that is a result of me blundering my way through learning GJS, GTK+ and a bit of WebKitGTK+.
Documentation and examples for these technologies is thin, scattered, and more often than not out of date. Quite often you'll need to look up C APIs and make your best guess at what the GJS equivalent will be.
The good news is that GJS uses the Spidermonkey Javascript engine which is quite up-to-date. And GTK uses modern WebKit2 webviews.
That said, I'm kind of a Typescript fanatic so despite having modern JS at my disposal I decided to write everything in Typescript anyway.
npm i
npm start
Then go to http://localhost:3000/
in your browser.
npm run build
- Outputs webview app to
public/
- Outputs executable GTK/GJS script to
markread
First npm run build
, then:
./markread readme.md
To install to /opt/markread
:
npm run build
sudo mkdir /opt/markread
sudo cp markread /opt/markread/markread
sudo cp -r public /opt/markread
Now you can right-click a .md
file and set its default application to /opt/markread/markread
. Then double-clicking .md
files will auto-launch this app.
You can also open files using the "Open" button or drag & drop them into the window.
First, a big thank-you to Github user optimisme for providing these examples. Without them I don't think I would've gotten anywhere.
I could find no up-to-date GJS examples using WebKit2 that demonstrated communicating between a GJS app and its webview. After much searching and pleading for help, I found a way to do this that is 50% okay.
Here's the gist:
// GTK
const contentManager = webView.get_user_content_manager()
contentManager.connect('script-message-received::test', (self, message) => {
const data = message.get_js_value().to_string()
print(data)
})
contentManager.register_script_message_handler('test')
// Webview
window.webkit.messageHandlers.test.postMessage('Hello from webview!')
This requires that you basically "exec" a Javascript string from the GTK side which runs in the webview context. So on the webview side you might set up a global message handler function:
window.handleGtkMessage(data) {
console.log(data)
}
Then in your GTK app you can do:
webView.run_javascript('handleGtkMessage("Hello from GTK")', null, () => {
print('Ran webview script')
})
This has a fairly small size limit as I discovered, so in order to send larger messages (like markdown file contents) you'll need to break these messages into chunks. You can see my implementations in src/app/ipc.ts and src/webview/ipc.ts.
This is kind of a strange thing to do given that GJS provides its own module system of sorts. But it makes working with the Typescript compiler easier than trying to get it to understand types from GJS's imports
. I simply wrapped the stdlib imports in a module (see src/app/gi.ts) then imported them "normally". Otherwise I used regular ES imports for my own sources and let the compiler/bundler do its thing.
GTK, GLib, Gio, WebKit2 etc. are huge APIs. So, no, a full set of up-to-date types don't exist. But I see a valiant attempt was made a few years ago here.
This app is pretty barebones in its current state. Links don't work, it can't open images from your local file system, there's no syntax highlighting. At some point I'd like to add an editor as well. But for now it scratches my immediate itch which was to have a quick utility to open and read markdown files with decent formatting.