Hacker News new | past | comments | ask | show | jobs | submit login
Dijo: A terminal-based habit tracker written in Rust (github.com/nerdypepper)
342 points by catacombs on July 20, 2020 | hide | past | favorite | 112 comments

Please note that "cargo install" is intended for installing Cargo subcommands and Rust-related tools for developers, not for distributing general software to end-users. https://github.com/rust-lang/rfcs/pull/1200#issuecomment-120...

The final accepted version of that RFC makes no mention of this, and even contemplates Cargo install as an alternative to system package managers [1].

The comment you link uses Rust tools as a justification for adding “cargo install”, but doesn’t attempt to limit its applicability to other binaries.

[1] https://github.com/rust-lang/rfcs/blob/master/text/1200-carg...

Even if you're right, what are you arguing here? "Cargo build" makes it extremely easy to distribute executables, as do GitHub releases. And free I might add.

It it only the most lazy and selfish developers who would not utilize this. I am speaking as someone who has distributed both Rust and Go programs.

Even a once a year executable release would be better than just saying "build it yourself".

> It it only the most lazy and selfish developers who would not utilize this.

Please refrain from making ad-hominem attacks on people that make different decisions than you would, even if they’re anonymous.

Open-source developers make their own decisions for their own reasons. They donate their time and effort to provide something to the community, and only they are in a position to determine what activities are worth their time.

> It it only the most lazy and selfish developers who would not utilize this.

Are you calling the whole Gentoo community lazy ?

If anything, I'd consider them to be the opposite of lazy, since making sure that all software always builds properly on each of your users machines takes a lot of work (IMO much harder than only making sure that it builds on your package manager controlled servers), and Watts.

As long as projects are telling people to do it this way, as long as it’s the easiest way to do so, it’s going to happen and keep happening. An RFC doesn’t get to dictate how devs distribute their software nor how users install it. We see time and time again how devs try to tell users how they’re using their software wrong and that never does anyone any good. Face the reality, and try to understand how that happened and what you can do. A “don’t do that” isn’t good enough.

FWIW the few rust devs I know do it exactly like this.

Do keep in mind that this kind of thinking is kind of self-reinforcing; by using cargo to distribute software, you'll keep a certain group of users outside of your ecosystem, thus never seeing complaints.

I, for one, cannot install this on the latest Debian Stable, I'm getting 'failed to parse Cargo.lock file' errors with cargo. So since there's no other way for me to install this or try this out, that's it.

Now I could probably install a more recent cargo version, but really, should I have to? I'm not a rust dev at all, and it seems like a high tax to pay for installing a tool I don't even know I will really use. I'll also know that raising a support issue about this would come off as entitled, and I'm not too familiar with Rust's ecosystem so I don't know if I step on anyone's toes, so I won't do it.

This is exactly why the discussion linked above happened, and why the RFC text still does say

> It is expected that all major Rust projects will still invest effort into distribution through standard package managers, and Cargo will certainly have room to help out with this, but it doesn't obsolete the need for cargo install.

If you're not a Rust developer, expecting you to have cargo and the right toolchain installed is too high a burden.

> Now I could probably install a more recent cargo version, but really, should I have to?

You don’t have to: You always have the option of not using the tool. It’s provided for free, and it’s not reasonable to expect it to be appropriate for everyone (or really anyone except the developer).

If their chosen installation method makes it unsuitable for you, so be it.

(NB: I am not affiliated with and do not speak for this project)

Sorry if the choice of words was inappropriate, I agree that “should i have to” is not correct. I do not want to put a burden on any developer who puts their work out for free, I was merely trying to discuss the dynamics of what’s happening here.

I specifically stated that I do not want to raise any issues as that would be entitled behavior.

Not sure if `rg` or `fd` are of either cargo subcommands or tools for developers.

`rg` is distributed via multiple channels - most distros have packages for it.

I think they are installable both with cargo install and brew install, so it doesn't really matter :D

I just have to say how much I appreciate the design of this. You killed it. It reminds me of Ronin [0] or something you’d see on /r/unixporn [1].

Also, really cool that this is written in Rust!

[0]: https://100r.co/site/ronin.html

[1]: https://www.reddit.com/r/unixporn/comments/dekj2i/oc_a_spoti...

I love the terminal UI how did you create that

In other words, the author did a lot of hard work to shape a fairly general purpose UI library into a very neat design. Kudos!

There is also the font selection and the borderless terminal which improve the aesthetics Without that it could look like this https://i.imgur.com/TVwkQI0.png

But I agree, the author did really good job in creating a clean an visually pleasing UI only using text and standard symbols

So to make it look like in the demo, you have to tweak the settings of your terminal?

Perhaps terminals should have cascading style sheets ...

I always find myself wanting just a little more terminal text style control. Usually I’m left wishing I had either an alternative font mode or double sized text. (Double specifically to avoid breaking the X*Y text cell grid)

But little wishes for extra expressiveness aside, i really don’t think terminal UIs would benefit from anything like CSS. The terminal functions as my working environment. I rely on being able to visually pattern scan for errors, warnings, typical command output, time stamp and log alignment etc. I do not want anything messing with how I set all this up.

If this is all this is it actually doesn't look like a crazy amount of work to make cursive look good: https://github.com/NerdyPepper/dijo/blob/8b91a7c0b3d9bd4fac3...

I've avoided looking too deeply into cursive in the past because I naively assumed it would be difficult to make it look like like anything other than a late-90s BIOS, but this is exciting.

This looks like a "draw the rest of the fucking owl" thing. Yes, it's not a lot of manual work, but I wouldn't be able to do it at all because I don't have a sense for design.

It looks amazing do we have something similar in python

In pythonland, you get a whole slew of TUI widget libraries

Eg blessed https://github.com/jquast/blessed

This^! It looks amazing.


Where is this data stored? The Wiki completely glosses over this subject, and I cannot tell from the code where it might save anything to (to be fair, I have never written in rust).

They use the 'directories' crate (https://docs.rs/directories/3.0.1/directories/struct.Project...) to work out where the data directory should be, then write out to a json file. See 'src/utils.rs'

Looks like it is stored in

  Linux:   /home/alice/.config/dijo/habit_record.json
  Windows: C:\Users\Alice\AppData\Roaming\nerdypepper\dijo\habit_record.json
  macOS:   /Users/Alice/Library/Preferences/rs.nerdypepper.dijo/habit_record.json


I haven't run this, so perhaps the behaviour is different to what I'm expecting, but since it uses `XDG_DATA_HOME` (`data_dir` in the `directories` crate) I'd expect it to appear as

on XDG compliant Linux.

That's where it is for me, and not under ~/.config. It's a bit puzzling, because that's where I expected it to be.

In general ~/.config is only for config; data should be in ~/.local/share, but a lot of programs get this wrong and abuse ~/.config using it for everything.

Even worse are the programs which use it to cache runtime data; I should be able to add the entire ~/.config to a dotfiles repo without accidentally including personal data (other than that which might reasonably appear in a config file) or ephemeral data.

Fair enough, I guess this is actual program data rather than the config, you're right.

thank you!

On macOS/Linux you can always use opensnoop to find all files a process accesses. Helped me many times.

I tried various digital habit tracking tools, including mobile, web, and terminal based, and the only one that has worked for me is graph paper. It's fast and in my face next to my desk and I never forget to use it and see it all the time.

Can it track my time spent running vim in various folders? That would be useful for me since in some solo projects I don't really commit changes often.

I guess not by itself, but you can control it externally in the command line. You would have to write a daemon monitoring the folder yourself.


Or a vim plugin. :)

ActivityWatch with a custom watcher might help with what you're looking for. Here's a list of some existing watchers, it looks like there's a vim plugin for it (haven't used the vim plugin myself though).


Check out https://wakatime.com - keeps some pretty fun stats.

Yeah that is what I currently use

This is great! Simple and elegant. Just an idea, maybe you put a cheat sheet under :help command. It would be very useful for people fluent in vim.

Love it! Everything should live in the terminal

Everything should be exposed to the shell, IMO, which isn't quite the same thing.

Indeed, for example via OS IPC mechanisms like COM/XPC/DBUS/Binder, shared libraries.

While that's not what I had in mind, in principle yes.

That said, in my experience, trying to use a real programming language's REPL for shell-like things is (at best) almost as bad as trying to write a meaningfully sized program in a shell's language.

I've many times tried to pin down exactly why. I think it's mostly a matter of focus and the various affordances provided by the ecosystem that have in fact been developed over the past however-many years.

I wouldn't be terribly surprised if you've found a niche and setup where it works out great for you - the important things are compositionality and putting what you need close at hand.

You can do that relatively easy in the context of Apple and Microsoft platforms.

Sorry, I said a few things. Which "that" are you referring to?

Using Windows as example, have a REPL (e.g. Powershell, C#/F# interactive) that interacts with the OS via COM/UWP, DLLs, OLE Automation.

So you can from the confort of your REPL get the text selected in e.g. Excel, and use it as input for a function that was actually imported from a DLL for data conversions, for example.

Very contrived example, just to show my point.

Ya but who wants to use COM/XPC/DBUS/Binder?

With sufficient affordances - tab completion and whatnot - it might be fine?

I generally agree. Here's why I like terminal UI:

- The constraints force designers to use the space efficiently. That means less details like borders, shadows or hover effects which is relaxing.

- It has a (relatively) uniform look and feel and automatically uses my system colors through the terminal configuration.

But I don't think every GUI program needs to be TUI. Like, if it's a bad fit for your user base or inconvenient to use or implement for you, it's fine. Do what works best for you, not every app is equal.

(Aside from that, most of my "apps" are just shitty Bash scripts that store data in some ad-hoc plain text or JSON file, break when you look at them the wrong way and are hell to debug but I love it. Do give me a good non-interactive CLI or API if you can!)

I'm not opposed to GUI's, but they should function like Emacs or the Bloomberg terminal: efficient and dense display of information, keybindings, and preferably some way to input commands directly (where each keybinding is bound to command). Unfortunately, GUI apps today are all slow, based on electron, don't have any keybindings, and are designed with the assumption that the user is stupid.

TUIs could be designed in a similar way to GUIs, but the culture around their development is much different. So while TUIs aren't inherently better (and based on their limitations, they should be worse), they almost always are.

> are designed with the assumption that the user is stupid.

Probably because the average user is. I don't mean that offensively, but literally everyone on this site lives in a tech power-user bubble. The average user doesn't care to have a dense display of information, keybindings, and ways to input commands directly. They want an easy to use and nice looking app that does what they want.

these are not mutually exclusive

They generally are, as each feature adds more work and there's only so much time and money available. While this isn't exclusively the case (some things are universal), the more you work on a feature specifically targeted at power users, the less you work on features targeted towards the general population.

For an app that's specifically meant for and targeting power users, that might be an acceptable choice to make, but if you want to target "people", then you're likely not going to be investing in power user features.

I know right. The same old UNIX crustaceans still want to relive the glory days of 1970 with "Everything should live in the terminal" with the chaos of X11, spending countless time editing their dotfiles or starting silly 'Vim/Emacs is better' wars. That ship has sailed. If not, already sunk.

I found this toy to be very cute. Too bad my friends are not the typical software engineer that can use this. I'll just point them to a native macOS habit tracker on the app store instead. Friendly enough for them and efficient enough unlike the Electron alternatives.

Actual progress rather than re-creating the prehistoric 'good old UNIX days' or turning the users laptops into stove burners with many Electron apps running.

The more I lean into using the terminal and emacs for programming, the more productive I find myself becoming. I can learn one command-line tool and apply it to so many other things by way of the pipe.

In GUI-land, this is hardly ever the case. I can't compose different software together, which is something I do all the time with the shell.

There are certainly some tools that work better as GUIs, but there are also tons and tons that really are great as terminal tools. No, this may not be a very approachable design for the average non-terminal-user, but that doesn't mean we should decry those who will find it useful. It's okay for different people to use different things.

I think I don't agree with the top-level comment in this thread that "everything should live in the terminal", and instead I believe what another response to that comment said: "everything should be exposed to the shell". Being able to compose tools is a huge productivity gain for those of us who care to do it and are used to it.

Hardly ever the case in GUI-land? That doesn't sound right at all. You can do the same kind of piecemeal work with GUIs that you do in the command line. Unless every piece of GUI software you use has a proprietary file format (which isn't unique to GUI software) it's all composable. Photos, videos, text files, etc. are all interoperable.

One contrived but possibly very common workflow for video creators: snip out a piece of a video with one tool, record new video from webcam with another, edit an image with photoshop, create sound effects in sfx util, create/record music with another, import all of the above into video editor and export a composited/rendered out video, do more lossless video compression/reduction with another utility.

Things I cannot easily compose:

- Messages (macOS)

- Slack

- web browser

- various notes apps

- iTunes

- Discord

- plenty more

These are tools I use all the time throughout the day. There is no simple pipe-like interface that allows me to easily take the output (graphical display) and pass it elsewhere to do something with it. In the terminal, everything shares a universal output system: text.

GUIs are not composable in principle. Sure, there are some workflows where you can do it, but that is not generally the case because they lack this common interface as a standard. CLI tools, on the other hand, have the standard of text output.

Except when those CLI applications happen to use curses, conio, or TTY escape codes for their output.

It is like the "Everything is a file", except when it is not.

Right, my point is that most CLI applications use text as output, versus most GUI applications do not.

Saying "Your point isn't true when there are exceptions" is a lazy argument, honestly. It is overwhelmingly the case that CLI applications use text as output, and my original point was specifically about how I wish this were more often the case with GUI applications — that you could somehow interface with them and compose them in the same way you generally can with CLI applications.

> In GUI-land, this is hardly ever the case. I can't compose different software together, which is something I do all the time with the shell.

Assuming those programs have been written to be usable from the CLI to start with.

Likewise GUI applications can be written to be automated by REPL environments automation, specially if the OS exposes application IPC like COM, DBUS, XPC, Binder, REXX, ....

From the perspective of UX of a power user, you’d need to convince me that all of these Electron apps is “progress”.

Also not, Electron apps are Windows HTA revisited, not willing to do the right stuff.

And yes even Microsoft does it, but what to expect when younger teams have the cool ideas to rewrite VS installer with node or use it to drive VS plugins.

Still not every graphical application is Electron based, whereas in what concerns the UNIX terminal hardly anything has changed in 50 years.

I think both GUI and TUI applications have their place. For developers and people who are comfortable with it, a CLI can be really extensible, allowing for every application to be opened or used instantly from the same location, and you can automate series of processes. GUIs have their place too. Some applications are more ergonomic with a GUI. I think the two of them can live in harmony.

Everything a UNIX cli does can be done better in a REPL.

Modern UNIX has the necessary IPC tooling for REPL workflows like on Xerox Workstations REPL, Amiga REXX, Oberon, Powershell/COM/.NET, Inferno, yet the large majority uses it hardly any different from V6.

Progress isn't about having pretty apps. It's about giving people what they want.

I want a thing in my terminal that I can use to track my habits

Sure, that's what you want.

I would argue that people want a more traditional app instead, with what I'm sure you'd consider a bloated and inefficient GUI. Considering that most people don't even know what a terminal even is, and that form regularly trumps functionality in day-to-day lives.

Then they already have multiple options for them to chose from...

The parent comment is implying that people don't want "pretty apps" and want simple functional apps like this exclusively.

I am arguing that what the parent commenter wants is valid, but is likely not what the general population wants.

In that respect, not sure how exactly your comment is relevant.

I don't think the parent comment was speaking for anyone but themselves. They expressed a preference, it was rejected as opposed to "progress". The comment about progress being giving people what they want was a refutation of that - like, "it can't be progress for me if it's not what I want." The fact that other people may want what they've been given is great - for them, progress! but it's also irrelevant to the point being picked at.

Perhaps I'm being overly charitable to the original commenter.

It is not about then terminal, rather using it as if the world hasn't changed since V6 came out.

Ignoring REPL based workflows, structured IPC with GUIs apps for automation, ability to use any library directly, cramping text into a little window in a high definition screen.

Could you point me to some examples of what you mean by a "REPL-based workflow"?

Yes, use a language REPL, whatever you do with pipe in UNIX shell, is done via function calls or composing operators like |> in F#, or -> threading macros in Lispy languages.

Then since it is a full programming language REPL, not only you have text, there is also structured data to act upon.

On top of that comes the capability to directly access dynamic link libraries, the libraries of the language being used, and when the OS exposes it, application automation APIs.

So you can do stuff like select an open application, or something inside it, then switch to your REPL and execute some script over that selection.

Basically you open something like Jupyter Notebooks on the OS, and interact in a graphical way with everything that is running, not just executables that can only talk text via stdio.

Some real life examples, were the Xerox PARC workstations (Interlisp-D repl, Smalltalk transcript, Mesa/Cedar devenv), AmigaDOS shell with REXX, OS/2 with REXX as well, Native Oberon with its command modules, and for something more up to date, Powershell with COM/DLL/.NET/OLE Automation/WMI integration, AppleScript / Automator.

In modern UNIX clones something similar could be achieved via DBUS, KParts and a scripting language of your liking, like Python, Ruby whatever, but it remains a niche thing.


If you are interested in a Web or Mobile (PWA) version: https://github.com/kissgyorgy/every-day-calendar

Funnily enough “un dijo” is short for “digestif” in french.


And it means “he/she/it says” (or the passive-voice “it is said”) in Spanish.

More like the past voice. "Dijo" -> he/she/it said. The passive voice it's "fue dicho" (he/she/it was been told).

Said can get a different meaning, such as the reflexive voice of "decir" (fué dicho) -> it has been said.

Though that would be "un digeo" (it's mainly a saying, not something people write often, so it doesn't matter that much)

Does anyone have any idea, what font the screenshot is in ?

Looked up the author's dotfiles repo[1], looks like it's Iosevka.

[1]: https://github.com/NerdyPepper/dotfiles/

Looks like Iosevka to me.

Wow, I tried to solve a similar problem in a similar way (command line based progress tracker) with a small personal project called Trackstar: https://github.com/dorkrawk/trackstar but this is SO much nicer!

for those looking for another open source task tracker, taskwarrior[1] is a good cli option. You can use VIT[2], curses-based front-end to taskwarrior. I don't use VIT, but taskwarrior integrates nicely with vimwiki using taskwiki[3].

[1] https://taskwarrior.org/ [2] https://github.com/scottkosty/vit [3] https://github.com/tools-life/taskwiki

wow, I had no idea terminal UI can look good.

The "fully scriptable" link (configure dijo to track your git commits!) seems to be broken.

Wondering if and how this could team up with orger. Could be an effient combo.

Great work. Love it.

Very cool! Did you consider writing it in Go?

Cool piece

I can't shake the feeling of how ugly Rust code looks in comparison to Python, Clojure and Go.

Eh, eye of the beholder. The stronger type system and more verbose syntax certainly makes the code look different. In a way though, it makes the code much more readable. To pick on Python, the Rust code is a lot more _specific_ in what it is going to do, I like that when I am maintaining a code base, it is easier to work on and understand. They are also targeting totally different use cases, so I understand differences of opinion depending on what kind of problem you are trying to solve.

I had the opposite opinion.

It looks like the best mix of abstractions like first-class Result, Option, Future, and Trait with some of the best performance.

In Go, I write twice as much code for code that's slower than Rust. I can't even reuse code without copy and paste. Python and Clojure don't even have Rust features. Python doesn't even have .map. Go is barely statically-typed (bet you're gonna use interface{} implementing this too), Python and Clojure aren't at all -- so that's also going to be a source of gut-reaction "whoa this must be complex".

The code looks very pleasing to me.

As I python dev I feel kinda the opposite: rust is surprisingly pretty with the exception of massive overuse of shift key to the point where I'd consider it a health hazard.

The only other low-level language that is pretty that I found is nim.

Nim is nice. I Don't Like It™ because it compiles to C, instead of a True™ compiler intermediate representation, but it's a solid language.

Ditto, as a Python dev I find Rust a lot prettier.

I've started using mypy in all Python projects, but it's a joke of course compared to proper strong typing.

A matter of perspective IMO. Before I learned Rust it looked messy but now that I know it I don’t think that at all. In fact the way you can use match statements and Result<T> structs make it quite beautiful to me.

as a fan of clojure you must be familiar with how people dismiss lisps because of the parens.

some of the complexity of Rust is just necessary to get C speed with memory safety, some is just not being used to the “parens”

The rust community's insistence on ending every sentence "written in rust" is only slightly more annoying than the python community's "for humans" fetish.

We are a community of craftspeople and engineers. What something is built with is something 99% of us want to know. Usually what something is built with and how it was built is frankly the only interesting thing to talk about.

I don't want a cli habit tracker, but I'm still here looking at how they built it, bikeshedding with my commiserators.

You may be more interested in Product Hunt. Not sure I understand your complaint, though. Makes me think that you would leave it off of your HN submission in some weird masturbatory idea of modesty. "Well, so what was it built with?" "Oh, I couldn't say ;)"

I kind of like each community having a shared sense of pride and ownership in their respective spaces.

this is a tech forum, it is common for the tech stack to be mentioned here when showcasing a product, whether it was written in Rust or a lesser language. (last sentence is a joke, stay calm)

Make a userscript:

  document.querySelectorAll(".storylink").forEach(link => link.innerText = link.innerText.replace(" written in Rust", ""))

Because there is a whole set of people that believe that Y is only possible when written in X, so we need to create proofs that isn't so, which leads to written in Z, regardless of what language Z stands for.

In this case, a Todo list.

Well, I was answering to the general issue.

It all boils down to... Rust compiler itself is written in Rust, and Python is made for humans.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact