From ef3273f4d5dad5bf08e26843fe1efd74310a2c18 Mon Sep 17 00:00:00 2001 From: Nathan Fisher Date: Tue, 26 Jul 2022 13:44:59 -0400 Subject: [PATCH] New posts --- content/gemlog/re:_programming_languages.gmi | 46 ++++++ content/gemlog/some_thoughts_on_vala.gmi | 151 ++++++++++++++++++ content/gemlog/vapad_0.1.0_prerelease.gmi | 34 ++++ .../gemlog/workflows_tooling_and_bloat.gmi | 97 +++++++++++ 4 files changed, 328 insertions(+) create mode 100644 content/gemlog/re:_programming_languages.gmi create mode 100644 content/gemlog/some_thoughts_on_vala.gmi create mode 100644 content/gemlog/vapad_0.1.0_prerelease.gmi create mode 100644 content/gemlog/workflows_tooling_and_bloat.gmi diff --git a/content/gemlog/re:_programming_languages.gmi b/content/gemlog/re:_programming_languages.gmi new file mode 100644 index 0000000..163e3a7 --- /dev/null +++ b/content/gemlog/re:_programming_languages.gmi @@ -0,0 +1,46 @@ +Meta( + title: "Re: Programming Languages", + summary: None, + published: Some(Time( + year: 2022, + month: 7, + day: 25, + hour: 22, + minute: 15, + second: 34, + )), + tags: [], +) +--- +Blippy writes: +> The Pi0 is a slow machine, so compiling Go code is actually pretty painful, despite the language having a reputation for fast compile times. + +=> gemini://tozip.chickenkiller.com/2022-07-25-pl.gmi Blippy: Programming Languages + +He goes on to list a few C "competitors" and asks if there are any more. He mentioned most of what I would have, although I would point out that (as much as I love it) Rust has terrible compile times. I can only speak to languages that I have some experience with, so I'll share one modern and one old that are worth considering. + +## Nim +Nim transpiles to C, so it runs pretty much at C speeds. It's most striking feature is the Python-like syntax, which a lot of people will appreciate. But there are a number of other novel features that I liked about it when I tried it out. It has what is known as Universal Function Call syntax, which means that I can treat a function which takes a certain type as it's first argument as if it were a method on that type. +``` +// this... +myfunc(a: sometype) +// can be called like this... +a.myfunc() +``` +I also appreciated the fact that a program's entry point isn't automatically main, so you can write a program that will function as a standalone binary if it is compiled alone, or as a library if it is compiled as part of a larger program. Compile times are pretty good. C interop is easy. + +=> https://nim-lang.org/ Nim language homepage + +## Fortran +I'm not kidding, check out Fortran. It compiles pretty damn quickly and runs on par with C for speed. It's quite a different syntax if you're coming from, well, pretty much anything else, but even as old as it is and with as small as the core language is, I've found it complete enough for getting things done. + +Interesting, there is an effort underway to modernize the language and attract new users. They now even have a Cargo and Npm inspired package manager, fpm, which I found works flawlessly. There is no "standard library", only a small collection of compiler builtins, but they're enough to get a lot done. Fpm has also led to a growing ecosystem of useful libraries to pick and choose from. Concurrency is possible, and the compiler GFortran theoretically supports all of the targets that GCC does. + +=> https://fortran-lang.org/ Fortran language homepage + +## Bonus: FreeBasic +This is a nostalgia inspired bonus. My first computer, like a lot of kids growing up in the 80's, was a Tandy TRS-80. It was primitive, ugly, and gave me a headache if I stared at the screen for too long. That said, I had a lot of fun abusing GOTO in order to write choose your own adventure style games in Basic. + +FreeBasic is surprising. Like Nim, it transpiles to C and then from there compiles to native code. And yes, you can actually write usable programs this way - the compiler itself is written in FreeBasic. While I'm offering this as a bit of a tongue in cheek answer, it's still pretty cool. + +=> https://freebasic.net/ FreeBasic homepage \ No newline at end of file diff --git a/content/gemlog/some_thoughts_on_vala.gmi b/content/gemlog/some_thoughts_on_vala.gmi new file mode 100644 index 0000000..e9f80c7 --- /dev/null +++ b/content/gemlog/some_thoughts_on_vala.gmi @@ -0,0 +1,151 @@ +Meta( + title: "Some thoughts on Vala", + summary: None, + published: Some(Time( + year: 2022, + month: 7, + day: 23, + hour: 15, + minute: 17, + second: 42, + )), + tags: [], +) +--- +I've been aware of Vala for a pretty long time now. It was first brought to my attention back when I regularly used Puppy Linux, as Barry Kauler had begun using and promoting it's sister language, Genie, for some small utilities in that distro. At the time, I wasn't confident enough in my own ability to have tried to progress much beyond shell scripting, so I never got around to trying it out myself. Recently it's been on my radar again, after seeing a number of interesting projects written in Vala (including a couple of Gemini browsers). I figured I really should investigate a bit more. + +## What is Vala? +To understand the point of Vala, it's helpful to dig into some of the underpinnings of the Gnome stack. Glib is a fairly broad spectrum base library which provides a lot of data structures and features which are taken for granted in most modern languages, but not provided by Libc. One of the more influential components of Glib is the GObject system, which provides an object oriented framework for C. However, as C itself was not designed with object oriented programming in mind, using the interface from C is pretty clunky at times and involves quite a lot of boilerplate. This is where Vala comes in. + +Vala is a C# inspired language based around GObject, which provides an interface to the Gnome stack that is much simpler than the C interface and was designed with Object Oriented concepts right from the beginning. It compiles down to C code, which is then compiled to native binaries, and does not impose a runtime of it's own. What that means is that Vala programs run at pretty much the same speed as their equivalent C program. I'm not a huge believer in Object Oriented programming for every type of program one might write, but it does match pretty well with a traditional retained mode, event loop driven gui. And Vala seems incredibly easy to pick up if you already have some programming experience. + +## A note on Genie +Genie is, as mentioned previously, sort of a sister language to Vala. Both languages are understood by the Vala compiler and in fact the two languages can be mixed within the same project. The difference is that where Vala's syntax is purposely as close to C# as possible, Genie took inspiration from Python. In genie, instead of curly braces and semicolons to denote statements and blocks you use indentation and whitespace. Pretty cool, if you're into Python and want to slide into a compiled language with simlilar syntax. That's not me though. When I got serious about programming I started with C, and moved from there to Rust and Zig. So I'll gladly stick with curly braces and semicolons now because it looks "right" to my eye. + +## Getting started +Installing the Vala compiler, valac, on Arch was as simple as `pacman -S valac`. Most vala projects are also now using Meson and Ninja, which are both widely available in package repositories. If you should happen to need (or want) to bootstrap the compiler from source, it builds in a couple of minutes on a 4-core 7th gen I5. Definitely not a pig like Gcc or Clang (or Rustc or Zig). There is also a vala-language-server, which was also in the Arch repositoies. If you're using VScode there's a plugin, and Gnome Builder seems to also have very good Vala support. I use Neovim, so alongside the lsp support I added a syntax highlighting plugin. I'm using Packer, but other plugin managers should be similar. +``` +-- init.lua for Neovim (excerpts) +require('packer').startup(function(use) + -- omitting my other plugins.. + use 'arrufat/vala.vim' +end) +-- further down, add 'vala_ls' to list of language servers +-- As you can see, I have a number of other languages configured here +local servers = { 'clangd', 'rust_analyzer', 'zls', 'fortls', 'pylsp', 'vala_ls' } +``` +Obviously, you can go much more minimal if you like. Neovim with lsp has me spoiled and seems like a great compromise between an ide and a traditional modal editor. + +There are various tutorials online. I can't really speak to how good they may or may not be, because after a cursory look at a few code examples I just dove into writing a real program. In my previous post, I complained about the amount boilerplate that Gnome builder thinks is necessary to begin a project, but I decided to go with the project skeleton anyway just as a learning exercise, since it would give me some code to refer back to. After all, this is going to most likely be a throwaway project. Starting with a plain "Hello World!" window using Gtk4, I thought I'd use gtksourceview and create a tabbed text editor. + +Eva was my first experience with creating custom widgets in Gtk+ by subclassing an existing widget. This is a fairly complicated thing to do in Rust with a good bit of boilerplate and a lot of moving parts which are easy to get wrong. It took a lot of trail and error before I got comfortable with doing it. In contrast, when I went to create a custom "Tab" widget in vala, subclassed from a GtkBox, it was really straightforward. +``` + using Gtk; + using GtkSource; + +namespace Vapad { + public class Tab : Box { + public Box lbox; + public Label label; + public Button close_button; + public View sourceview; + + public Tab () { + create_widgets (); + } + + private void create_widgets () { + this.lbox = new Box (Orientation.HORIZONTAL, 5); + this.label = new Label ("New file"); + lbox.append (this.label); + this.close_button = new Button (); + this.close_button.set_has_frame (false); + lbox.append (this.close_button); + var image = new Image.from_icon_name ("window-close-symbolic"); + this.close_button.set_child (image); + var scroller = new ScrolledWindow (); + this.append (scroller); + this.sourceview = new View(); + scroller.set_child (this.sourceview); + scroller.set_hexpand (true); + } + } +} +``` +That's crazy simple compared with the equivalent Rust code. I'm having to retrain my brain to use "this" instead of "self" anyway since I've been using php for a paid project, but the syntax overall is really quite easy to understand and pick up. This is a composite widget, where we have a GtkSourceView widget packed into a ScrolledWindow packed into a GtkBox. The GtkBox is going to be the widget that makes up each tab, and the other Box "lbox" will be it's label, which has an internal label and close button. The project skeleton gave us a Window widget which was subclassed from a GtkApplicationWindow using an xml ui file to make a composite template. I removed the "Hello World!" label from the window and replaced it with a GtkNotebook in the ui file, and then added a "New Tab" button to the ui file as the notebook's action widget. Here's the relevant section of the ui file. +``` + + + 1 + 1 + 1 + 1 + 1 + + + Open a new tab + 0 + win.new_file + + + tab-new-symbolic + + + + + + +``` +Note that the "new_tab_button" has a named action already associated with it. Gtk's action system is nice and simple once you understand it. Like most things open source, it could be better documented. But basically, we create an action with that name, associate it with with the window and add a keyboard shortcut. There is then no need to retain a reference to the button in our window subclass, so that we can connect to the "clicked" signal, because the action will already be associated with button. As a bonus, we can add that same named action to a menu item and the menu item will then launch the action, and we'll have the associated shortcut displayed next to the menu item. You get a lot for just a little code. I absolutely hate XML and wish that Gtk+ used some other kind of declarative format for ui definitions, but it's this way because Gtk+ is a product of the late 90's and early 2000's and everything had to be XML around that time. + +Anyway, let's look at our Window subclass as it sits currently. +``` +namespace Vapad { + [GtkTemplate (ui = "/org/hitchhiker_linux/vapad/window.ui")] + public class Window : Gtk.ApplicationWindow { + [GtkChild] + private unowned Gtk.Notebook notebook; + + public Window (Gtk.Application app) { + Object (application: app); + } + + construct { + ActionEntry[] actions = { + { "new_file", this.new_page }, + { "close_file", this.close_page }, + }; + this.add_action_entries (actions, this); + this.notebook.page_removed.connect ( () => { + if (this.notebook.get_n_pages () == 0) { + this.close (); + } + }); + } + + public void new_page () { + var tab = new Vapad.Tab (); + this.notebook.append_page(tab, tab.lbox); + tab.close_button.clicked.connect ( () => { + this.notebook.remove_page (this.notebook.page_num (tab)); + }); + } + + public void close_page () { + var num = this.notebook.get_current_page (); + this.notebook.remove_page (num); + } + } +} +``` +It's kind of funny to me that the "close_page" function turned out to be so short in Vala. In Rust, getting the current page is a fallible operation (because maybe there is no tab) and Rust forces you to deal with it. In reality that isn't going to happen because I'm connecting to the "page-removed" signal of the notebook and closing the window when the last tab closes. I could actually turn the Vala version into a one liner. + +Similarly, setting up actions is much less verbose than in Rust. The Rust interface to Gtk+ quite heavily relies on macros for subclassing and related tasks, and it's overall not something that matches up well with Rust syntax, leaving gtk-rs programs looking very un-idiomatic looking. My Zig bindings to Gtk3 used in Zterm don't even allow you to do a lot of these things, greatly complicating the code and making it much more verbose to accomplish what are pretty simple tasks in Vala. Vala is showing here just how purpose built it is for this domain. + +The GtkApplication that was set up via the project skeleton is also subclassed from GtkApplication, although I'm not sure how much gain we're getting from that. I'm not going to show that file because this post is already pretty heavy on code. The only things that I had to add to it were setting up the keyboard accels for our actions and adding a first initial tab when the program is launched, by calling the "new_page" method on our instance of "Vapad.Window" which is the initial window. + +## Stopping here for now +### Status and thoughts +As it sits this editor isn't yet very useful. You can open new buffers and close them, and write to your heart's content. But you can't save a buffer to a file or open any files. The editor isn't taking advantage of any of the features that you get from GtkSourceView, like auto-indenting or syntax highlighting. Nevertheless, in just a couple hours I managed to go from a "Hello World!" project skeleton to a dynamic tabbed interface, in a language that I've never used before. I imagine once I'm up to speed a little better I could be very productive in Vala. I like it. I'm not ready to switch over to coding in Vala full time, but I'm sold on adding it to my arsenal. + +I think I'm going to take this just a bit further on a "for fun" basis and add the ability to open and save files, as well as adding syntax highlighting, line numbers and auto-indentation. I may even throw the code up on Codeberg once I consider it functional enough. But I'm not going to take it much further than that because it's not really a program that I would get much use out of myself, since I always seem to fall back to terminal based editors. But it will be a good way to get a little bit more comfortable with Vala and to get to know the Gnome stack a little better. Hopefully someone else finds this interesting as well. \ No newline at end of file diff --git a/content/gemlog/vapad_0.1.0_prerelease.gmi b/content/gemlog/vapad_0.1.0_prerelease.gmi new file mode 100644 index 0000000..2a10945 --- /dev/null +++ b/content/gemlog/vapad_0.1.0_prerelease.gmi @@ -0,0 +1,34 @@ +Meta( + title: "Vapad 0.1.0 prerelease", + summary: None, + published: None, + tags: ["vapad", "vala", "programming"], +) +--- +So one of the Linux distros that I used a lot in my early days was Puppy Linux. Around the time I started with it, Puppy had two graphical text editors, Leafpad and Beaver. Leafpad was basically what you'd get if you were copying Notepad's interface using Gtk+. It's extremely simple and no frills. Even after moving away from Puppy, I continued to install Leafpad on whatever system I was on and made sure that it was the program used to open any text file when clicked on in a file manager. I did this for a rather long time, until I sat down and actually learned Vim. + +Xfce at some point adopted the Leafpad codebase and began improving upon it as their Mousepad editor. Mousepad initially only added tabs, and then syntax highlighting. And then, after a while, a funny thing happened. The number of things that you can configure on Mousepad blew up, and it stopped being in any way reminiscent of Leafpad and started looking like a mini Gedit. It's pretty nice, if that's your thing, but to me it's gone way beyond what I think that sort of program should be. Funny that I have an opinion on graphical text editors considering I use Vim almost exclusively, but there it is. + +Anyway, Vapad 0.1.0 is out. My plan with Vapad is to take the essence of what Leafpad was and say, what would this be if it were made today? Well, not having tabs is just silly, and I'm not sure that there's ever a time when you *don't* want syntax highlighting on, so the editor is going to set up some sane defaults for you, let you change just a couple of things like fonts and colors, and use a more modern interface. That is, instead of a menu bar you get a GtkHeaderbar with an open and save button in it and a hamburger menu. It fits right in on Gnome and doesn't look too out of place in Xfce. There's no setup to be done to get it working the way that you want it to. You just open files and edit them, and the program should stay out of the way. + +## What's working now +* Opening, editing and saving files +* Basic search forward and backward with wrapping on by default +* Tabbed interface +* Keyboard shortcuts for all currently implemented actions + +## What's planned but not implemented +* Advanced search, including search and replace and regex +* The preferences window doesn't exist yet. When it does, it'll be short and sweet (see below). +* When opening files, the chooser should be set to the directory containing the current file. Easy fix, probably next. +* I plan to add any previous searches to the completions for the search bar. +* Printing + +## Planned preferences +* Tab location +* Font +* Color scheme + +What I don't plan to have is a million little checkboxes to tun features like line numbering, syntax highlighting and auto-indenting on or off. My thinking is that those kinds of comfor features can just be left on at all times, because the first thing that most people do is turn them on anyway. Like I said, sane defaults and a simple interface. + +=> https://codeberg.org/jeang3nie/vapad/releases/tag/v0.1.0 diff --git a/content/gemlog/workflows_tooling_and_bloat.gmi b/content/gemlog/workflows_tooling_and_bloat.gmi new file mode 100644 index 0000000..b044435 --- /dev/null +++ b/content/gemlog/workflows_tooling_and_bloat.gmi @@ -0,0 +1,97 @@ +Meta( + title: "Workflows, Tooling and Bloat", + summary: Some("Some thoughts on why newer developers are doomed to be working uphill."), + published: Some(Time( + year: 2022, + month: 7, + day: 21, + hour: 22, + minute: 24, + second: 39, + )), + tags: [ + "software", + "gnome", + "tooling", + ], +) +--- +I like to try out languages from time to time. I've dabbled in a lot of different ones, some modern and some very old, and find it fascinating how after the first few experiments each succeeding language becomes easier to learn. That's not the point of this post, although it's always a fascinating subject. Rather, it's merely what got me thinking about tooling today. + +I've got a bit of a history with Gtk+. My first graphical programs were written back when I was running Puppy Linux and contributing to it regularly. Back then, we used gtkdialog and abused shell scripting to the extreme. I consider that path a bit of a dead end, but it made the concepts familiar when I revisited writing graphical applications later on, this time in compiled languages. I've played around with Gtk+ in Python, C, Go, Fortran, Zig and most commonly in Rust. But recently I thought that I would try out Vala, as it seems to be almost purpose built for the task (being based around Glib and GObject). It's actually quite a nice language for the task, although I wouldn't reach for it in any other context. Having actual namespaces makes the code more readable than C, and the amount of boilerplate is also reduced. + +That is, until I decided to try out Gnome Builder again... + +## A typical project skeleton +I'm sure that most people have their own opinions on what a nice minimal project skeleton is. It's also kind of domain specific, as a desktop application will have need of files that a command line utility won't. For my Rust and Gtk+ projects, a minimalist project tree would look like this. +``` +. +├── Cargo.toml The Cargo manifest, for the build +├── data +│   ├── app.svg An application icon +│   └── app.desktop The freedesktop.org .desktop file, for WM menus +├── LICENSE.md The project license +├── README.md Brief description of the application +├── src +│   └── main.rs The program entry point +└── xtask This subdirectory is used in packaging, and is + ├── Cargo.toml entirely optional (see below) + └── src + └── main.rs +``` +The xtask subdirectory contains the source for a separate binary which is used to perform packaging tasks. It wasn't my idea originally, but one that I've adopted for all of my Rust projects. This binary copies all of the required files into a staging directory, generates smaller png icons from the original svg, generates shell completions and Unix man pages, etc. It automates those things that Cargo itself doesn't do natively. I could use instead make, or meson, or any number of other build tools. The advantage of the xtask binary is that it doesn't fall down in the event that some tool that existed on the developer's machine isn's available on the packager's machine. The xtask binary knows how to read svg and write a png, and how to create shell completions from the CLI definitions, etc. It's a nice system, I think. + +## Gnome Builder's project skeleton +Starting a new Gtk+ project written in Vala from Gnome Builder creates this tree. +``` +. +├── COPYING +├── data +│   ├── icons +│   │   ├── hicolor +│   │   │   ├── scalable +│   │   │   │   └── apps +│   │   │   │   └── org.hitchhiker_linux.app.svg +│   │   │   └── symbolic +│   │   │   └── apps +│   │   │   └── org.hitchhiker_linux.app-symbolic.svg +│   │   └── meson.build +│   ├── meson.build +│   ├── org.hitchhiker_linux.app.appdata.xml.in +│   ├── org.hitchhiker_linux.app.desktop.in +│   └── org.hitchhiker_linux.app.gschema.xml +├── meson.build +├── org.hitchhiker_linux.app.json +├── po +│   ├── LINGUAS +│   ├── meson.build +│   └── POTFILES +└── src + ├── application.vala + ├── gtk + │   └── help-overlay.ui + ├── main.vala + ├── meson.build + ├── app.gresource.xml + ├── window.ui + └── window.vala +``` +Ok then, uh, that's a lot. And tokei counts 407 lines of code. Doing the same but for a Rust Gtk+ project results in a further 162 lines of code and 4 more files. Some things I find interesting: +* There is not only an application icon but a symbolic icon. Why? +* The appdata.xml, gresource.xml and gscheme.xml files are pretty well Gnome specific. +* There are four meson.build files, when it's not really required to use Meson at all. Builder assumes you want to use Meson. Maybe you don't. +* Builder assumes that you want to use ui definition files and not just code your interface in Rust. +* Builder assumes that you would subclass gtk::Application and gtk::Window. Eva uses some subclassing, but not for it's main window or application. OxTerm subclasses it's main window, but not it's application. Gfret doesn't use subclassing at all. +* Builder makes another assumption that you want to have a help window, which just displays the application shortcuts. Since these shortcuts are displyed next to their corresponding menu entries, that's of dubious utility. +* Builder assumes that we want to distribute this application as a Flatpak and includes the tooling to do so. + +A lot of this comes down to preference, and I do realize that I'm picking on Gnome Builder here when they've obviously designed it around creating applications specifically for Gnome. You get the same sort of boilerplate heavy project template out of, say, QT Designer, but optimised for a different workflow. That said, Gtk+ is pitched as a general purpose, platform independent toolkit. It can be used outside of the context of Gnome, and in fact is used that way a lot. Builder actually gives you a choice of several types of project to create, one of which is plain Gtk+ and one of which is Gnome. And the examples I already gave are the plain Gtk+ variety, not Gnome. So why all the Gnome-ey boilerplate and Gnome-ey assumptions about what to include and how to build it? + +## Beyond skeletons +Great tooling can do a lot to make a development experience smoother and more productive. That said, always abstracting away to a higher level comes with tradeoffs, and in particular if you don't learn how to use the underlying tools in the first place. I learned to use Git on the command line before encountering any kind of IDE integration. I've written Makefiles by hand and know how to invoke Gcc directly. When learning Rust I learned how to use Rustc before learning Cargo. But that's because I came up in the days when we had to write an Xorg config file by hand and often had to intervene when the boot process didn't load all necessary modules. Younger folks haven't had those experiences. The most used and recommended editor is VScode, not Vim. Linux is pretty easy to use now, too. Generally, you install it and everything works on first boot, or at least close enough. It's been years since I had to, say, use ndiswrapper to attempt to get a USB network interface working that doesn't yet have a native driver. + +I think that anyone who wants to use their computer in anger owes it to themselves to dig beyond the numerous outer layers that we keep erecting to make things "simpler". I'm not against automation. In fact, my description of how I use xtask in my Rust workflow shows how committed I am to automating packaging. But I don't think it's a good idea for young programmers to start their journey with an IDE. I'd rather see them start with Vim or Emacs in their plain vanilla configuration, and then over time build up a personalized workflow that automates those things that they feel are a waste of their time. If they instead start out with someone else's idea of a good starting point it is destined to be bloated, and will only acquire even more cruft as time goes by and developers add even more "good ideas". + +I love everything that the Rust ecosystem gives in the way of tooling, but at the same time I kind of miss writing C and the only documentation being manual pages. You had to learn how to use the man command in order to find the info that you needed, but it was there in the terminal, and you were already in the terminal running your editor and compiler. I still think that Make gets a bad rap, because frankly it can do just about anything and it's pretty easy to learn. Note that I'm referring to Make, not to Gnu Autotools. Autotools was the worst kind of abuse of shell scripting imaginable. I really strongly dislike that modern IDE's abstract away the actual commands used to invoke the compiler. I'd even go so far as to recommend that new developers learn how to manually invoke the linker, as there is going to come a time when you run into an incorrect linker command being your build system's failure and you need to be able to troubleshoot it. + +Could this all be filed under "old man yells at clouds"? Well I suppose that it could. But this is, like, my own space to do with as I want... \ No newline at end of file