Emacs: How to add bookmarks to files and directories

Very useful feature of Emacs: You can bookmark directories and files and switch between them quickly.

To add the current dired directory to bookmarks, press M-x r m in dired, then type bookmark name.

To add bookmark to a file, use the same keystroke in a window with a file.

To jump to a bookmark press M-x r l, move to required bookmark in the list and hit enter

Far2l file manager

Far2l is a port of Far Manager v2 that runs on Linux and Mac.

Installation

On Linux distros, first search for far2l package. If it’s not awailable, you have to build it by yourself.

On macs, use the brew package manager:

brew install --cask far2l

Screenshots

Far2l main screenshot

Usage

Interface is pretty the same, but of course far2l is not so much powerful as original Far Manager.

Basic commands for file manipulations are the same as in Far:

  • Tab - jump between left and right panels
  • F5 - Copy file under cursor/selection to the opposite panel
  • F6 - Move file under cursor/selection to the opposite panel
  • Shift-F5 - Create copy of a file file in the same panel
  • Shift-F6 - Rename current file
  • Enter - open file
  • Shift+arrows up/down - select files
  • F3 - View file under cursor
  • F4 - Edit file under cursor

Development state

As of 2024, far2l seems actively developed.

JS: focus on the first input with an error

In this article, I’ll show you how you can easily focus on the first element with an error on your form. The methodology is framework-agnostic, so you can easily adopt it to your framework (if you use any).

TL;DR

Add a data-error attribute to an element if it has an error and then focus on it with querySelector + focus().

Project setup

We’ll use vite + vanilla ts for our project:

npm create vite@latest my-vue-app -- --template vanilla-ts

Now we need some cleanup - remove all content from the styles.css file as well as from the main.ts.

Create a form

First, let’s add markup for our form (main.ts file):

import './style.css'

document.querySelector<HTMLDivElement>('#app')!.innerHTML = `
<div class="personal-form">
  <div class="text-input">
    <label for="name">Name</label>
    <input id="name" type="text">
    <div class="error-label" id="error-name"></div>
  </div>

  <div class="text-input">
    <label for="email">Email</label>
    <input id="email" type="text">
    <div class="error-label" id="error-email"></div>
  </div>

  <div class="text-input">
    <label for="address">Address</label>
    <input id="address" type="text">
    <div class="error-label" id="error-address"></div>
  </div>

  <div class="text-input">
    <label for="passport">Passport</label>
    <input id="passport" type="text">
    <div class="error-label" id="error-passport"></div>
  </div>
  <button id="send"> Send </button>
</div>
`

And this is our css (style.css file):

:root {
  font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
  line-height: 1.5;
  font-weight: 400;
}

.text-input {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.personal-form {
  display: flex;
  flex-direction: column;
  max-width: 70ch;
  margin: 0 auto;
  gap: 1rem;
}

.error-label {
  color: red;
  font-size: 14px;
}

.error-label:empty {
  display: none;
}

The most important thing here is the error-label class - we hide error blocks if they’re empty( with the help of the empty pseudo-class).

Now our page looks this way:

form image

Define data structure

We store each field’s value in its own variable:

let name = ''
let email = ''
let address = ''
let passport = ''

Errors are stored in a single object:

const errors = {
  name: '',
  email: '',
  address: '',
  passport: '',
}

We need to update our variables’ values when text in fields is changed:

function updateValue(inputId, cb: (value: string) => void) {
  document.getElementById(inputId).addEventListener('input', (e: Event) => {
    const value = (e.target as HTMLInputElement).value
    cb(value)
  })
}

This function adds a listener to the input’s input event and we exute it for each of our fields:

updateValue('name', (value) => name = value)
updateValue('email', (value) => email = value)
updateValue('address', (value) => address = value)
updateValue('passport', (value) => passport = value)

When the text in a field is changed, a callback function is executed, which in its turn assigns this value to a corresponding variable.

And finally, code that is responsible for the form’s logic:

function onSubmit() {
  validate()
  displayErrors()
  focusOnError()
}

document.getElementById('send').addEventListener('click', onSubmit)

The idea is simple -

Now we need to implement each from these steps.

Add validation

Our validation logic lives in the validate function:

function validate() {
  // First of all, reset all error messages
  for (const key in errors)
    errors[key] = ''

  if (!name.length)
    errors.name = 'Required field'
  else if (name.length > 30)
    errors.name = '30 characters max'

  if (!passport.length)
    errors.passport = 'Required field'
  else if (passport.length !== 13)
    errors.passport = 'Pasport id should be 13 characters long'
}

It validates only two fields, but that is enough for the demonstration. You can read article about validation with the help of the zod framework here. It is worth noting that this function doesn’t do anything with visual representation on the page - it only validates variables’ values and writes error messages to another variables.

Display errors

After our form’s data is validated, it’s time to display errors if there are any. The algorithm is simple: we iterate over the errors object and update inner text of the error labels with corresponding value. Each error label’s id contains field name (error-nameerror-passporterror-email etc), so we can rich them with document.getElementById function.

Besides that, we are adding a data-error attribute to the input fields which are invalid.

So, here it is:

function displayErrors() {
  for (const key in errors) {
    setErrorValue(key, errors[key])

    if (errors[key])
      document.getElementById(key)?.setAttribute('data-error', errors[key])
    else
      // Don't forget to remove attribute from the input field if its value
      // is correct
      document.getElementById(key)?.removeAttribute('data-error')
  }
}

setErrorValue function searches for an error label and updates its text:

function setErrorValue(field: string, error: string) {
  const el = document.getElementById(`error-${field}`)
  if (el)
    el.innerText = error
}

Set focus on a field with an error

We use document.querySelector to get the first element in the DOM tree with a data-error attribute and set focus on it:

function focusOnError() {
  document.querySelector('[data-error]')?.focus()
}

That’s all! Now, on submit, focus will be set on the first field with an invalid value:

validation result

Full source code

src/main.ts:

import './style.css'

document.querySelector<HTMLDivElement>('#app')!.innerHTML = `
<div class="personal-form">
  <div class="text-input">
    <label for="name">Name</label>
    <input id="name" type="text">
    <div class="error-label" id="error-name"></div>
  </div>

  <div class="text-input">
    <label for="email">Email</label>
    <input id="email" type="text">
    <div class="error-label" id="error-email"></div>
  </div>

  <div class="text-input">
    <label for="address">Address</label>
    <input id="address" type="text">
    <div class="error-label" id="error-address"></div>
  </div>

  <div class="text-input">
    <label for="passport">Passport</label>
    <input id="passport" type="text">
    <div class="error-label" id="error-passport"></div>
  </div>
  <button id="send"> Send </button>
</div>
`

let name = ''
let email = ''
let address = ''
let passport = ''

const errors = {
  name: '',
  email: '',
  address: '',
  passport: '',
}

function updateValue(inputId, cb: (value: string) => void) {
  document.getElementById(inputId).addEventListener('input', (e: Event) => {
    const value = (e.target as HTMLInputElement).value
    cb(value)
  })
}

updateValue('name', (value) => name = value)
updateValue('email', (value) => email = value)
updateValue('address', (value) => address = value)
updateValue('passport', (value) => passport = value)

function onSubmit() {
  validate()
  displayErrors()
  focusOnError()
}

document.getElementById('send').addEventListener('click', onSubmit)

function validate() {
  // First of all, reset all error messages
  for (const key in errors)
    errors[key] = ''

  if (!name.length)
    errors.name = 'Required field'
  else if (name.length > 30)
    errors.name = '30 characters max'

  if (!passport.length)
    errors.passport = 'Required field'
  else if (passport.length !== 13)
    errors.passport = 'Pasport id should be 13 characters long'
}

function setErrorValue(field: string, error: string) {
  const el = document.getElementById(`error-${field}`)
  if (el)
    el.innerText = error
}

function displayErrors() {
  for (const key in errors) {
    setErrorValue(key, errors[key])
    if (errors[key])
      document.getElementById(key)?.setAttribute('data-error', errors[key])
    else
      document.getElementById(key)?.removeAttribute('data-error')
  }
}

function focusOnError() {
  document.querySelector('[data-error]')?.focus()
}

src/style.css:

:root {
  font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
  line-height: 1.5;
  font-weight: 400;
}

.text-input {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.personal-form {
  display: flex;
  flex-direction: column;
  max-width: 70ch;
  margin: 0 auto;
  gap: 1rem;
}

.error-label {
  color: red;
  font-size: 14px;
}

.error-label:empty {
  display: none;
}

Pros and cons

  • Framework-agnostic, can be used with vanilla JS
  • Won’t work if html has non-default order of elements (because querySelector returns the first matched element)

Vue: How to check for a specific parent component

The problem: you want to make sure that a component is placed inside some other component.

The reason why you may want to do this is that your component has no sense when used outside its parent. For example:

<ContextMenu>
  <ContextMenuItem icon="home-icon" text="Home" />
  <ContextMenuItem icon="cut-icon" text="Cut" />
  <ContextMenuItem icon="paste-icon" text="Paste" />
</ContextMenu>

Here, the ContextMenuItem is usable only as a “brick” of the ContextMenu.

In such cases, you can use provide/inject:

  1. Provide a value in ContextMenu
  2. Inject the value in ContextMenuItem. If it’s not defined, throw an error.

Example

As usual, create an empty vite + vue + typescript project:

npm create vite@latest parent-component -- --template vue-tsc

First of all, we need a key for provide/inject functinos, so let’s add it. Create the key.ts file in the root of the project with this content:

import type { InjectionKey } from 'vue'
export const key = Symbol() as InjectionKey<string>

Then, in the components directory, create a ContextMenu.vue file:

<script setup lang="ts">
import { provide, inject } from 'vue'
import { key } from '../key'

provide(key, 'value')
</script>

<template>
  <ul>
    <slot />
  </ul>
</template>

Then, create a ContextMenuItem.vue file:

<script setup lang="ts">
import { inject } from 'vue'
import { key } from '../key'

const val = inject(key)

if (!val)
  throw new Error('ContextMenuItem can be used only inside ContextMenu component!')
</script>

<template>
  <li> Menu Item </li>
</template>

And finally, let’s show our ContextMenu component in the App.vue:

<script setup lang="ts">
import ContextMenu from './components/ContextMenu.vue'
import ContextMenuItem from './components/ContextMenuItem.vue'
</script>

<template>
  <div>
    <ContextMenu>
      <ContextMenuItem />
      <ContextMenuItem />
      <ContextMenuItem />
    </ContextMenu>
  </div>
</template>

Now, on our main page, we’ll see three “Menu item” strings, one per each ContextMenuItem. Open dev console, and make sure you don’t see any errors or warnings.

Everything works as expected - ContextMenuItem is inside ContextMenu. But if we remove ContextMenu component, our dev console will show us an error:

error from the ContextMenuItem component

Should I always check for such situations?

Of course no. Check for the parent component if you really need this. If you’re in doubt, I consider to update your documentation instead of adding more JS code to your project.

References

vue-tsc in watch mode

vue-tsc can be run in a watch mode and report any typescript errors as you change files in a project.

Simply run it with this command:

npx vue-tsc --noEmit --watch

Why you may want to use it? I personally prefer to disable any linter/LSP messages when I need more concentration on a task and I don’t want to be distracted by UI buzz that IDE or editor’s plugins create.

VSCode does it better than Sublime

I found a few things that VSCode does better than Sublime Text.

Creating new files from the sidebar

When you create a new file in the sidebar file navigator, VSCode asks for a filename first, and only then opens the file itself. In Sublime Text, after clicking on “New File” context menu item, new tab is opened, and you type a filename only when saving. Creating a file first is better, because in this case your file will have an extension, and proper mode and syntax highlighting will be used when you’ll start writing.

Sidebar position (Not actual anymore)

Update: In 2025, Sublime Text has an option to move the sidebar to the right side.

In VSCode, the sidebar can be moved to the right side. This is very useful when you often toggle the sidebar (on small screens, for example) - in this case your code is not shifted to the right side each time the sidebar is shown.

Vocaloid music genre

Vocaloid is a music genre where voice is synthesized with a software.

It’s named so because of the Vocaloid software, made by Yamaha, which synthesizes singing voices.

Hatsune Miku

Hatsune MikuWikipedia - Hatsune Miku is a character for a voice bank for Vocaloid, released in 2007.

Hatsune Miku

She is very popular, people go to her concerts, there are a lot of fan stuff with her - figures, posters, t-shirts, you name it. She’s not the only one or first virtual voice characters, by the way. MEIKO, for example, was released three years before Miku.

MEIKO

Hatsune Miku

Links

  • Vocaloid famdom wiki. Most probably the only resource you need to dive into the world of vocaloid program and music created with it.

Android apps that I think are great

A list of android apps I can recommend.

OLauncher

If you want a simple and elegant android launcher, Olauncher is for you. It removes all icons from the screen and allows you to add just 5 applications to the main screen. These apps are displayed as text - no icons. You can swipe up to see the full list of applications. Also supports swipe customization - for example, you can set left swipe to open contacts, and right to launch the camera.

Markor

Markor is a markdown editor with a lot of additional features, such as support for todo.txt format, export to pdf, html and image formats (and yet it’s not all available formats). Todotxt support is great - markor can move completed tasks to the archive file, so your todo.txt will be always clean. The “quick notes” feature is also a great idea - basically it’s just a simple markdown file, but in the app you have a separate button to open it quickly.

DroidFS

DroidFS allows you to create an encrypted container, where you can put all sensitive stuff. Supports wiping imported files from the phone memory.

Etar

A good calendar app. Nothing more, nothing less.

Foobar

The old good foobar music player.

Using JsDoc for typing

Typescript is a new standard in the Javascript world, and almost all tools and frameworks can deal with it now, but despite that, it’s also true that the existence of transpile step complicates development and hides actual code in a “black box”. In this post, we’ll see how we can write plain javascript code yet use typescript for type checks.

What is JSDoc

JsDoc is a tool that can generate API documentation from comments that formatted in a specific way, for example:

/**
 * Multiply two numbers
 *
 * @param {number} a - First number
 * @param {number} b - Second number
 *
 * @returns {number}
 */
function multiply(a, b) {
	return a * b;
}

In this example, we have documented a function and its parameters, as well as function and parameters’ types.

Beside simple cases, we can define array types, objects, type unions, export types from other files and packages, and all of that is done inside comment blocks. Following are examples of some JsDoc comments.

General syntax, parameters and return types

A Jsdoc command starts with the /** multi-line comment. Note that comments that don’t start with /** are not treated as JsDoc comments - /*** and /* comments won’t be parsed. Then documentation text goes. When we want to document parameters, we use @param tag:

@param {string} userName User name

@param tag has “{type} parameterName parameterDescription” form. To document return type, @returns tag is used:

@returns {number}

Optional parameters

We can make a parameter optional by wrapping it in square brackets:

/**
 * @param {string} [name]
 */
function printName(name="Name") {
	console.log(name);
}

Any type

/**
 * @param {*} value
 */

Default values

/**
 * @param {string} [somebody=John Doe] - Somebody's name.
 */

Documentation

Union types

Here, the id parameter may be string or number:

/**
 * Get user by id
 * @param {string | number} id User id
 */
function getUser(id) {
	//...
}

Arrays

/**
 * @param {number[]} keys - List of keys
 */

Complex types

We can define our own types with @typedef tag:

/**
 * @typedef {Object} User
 * @property {number} id - User's id
 * @property {string} name - User name
 * @property {string} email - User's email
 */

 /**
  * Get user's info
  *
  * @param {number} id User id
  * @returns {User}
  */
function getUser(id) {
    //...
}

As you can see, we can declare a type with the @typedef tag and then use it as if it’s a normal type.

Import type from another file

It’s often needed to use a type declared in another file. Taking our previous example, we may want to create a userHelper file, which will contain helper functions that use the User type. Re-defining the User type is a nonsense. Luckily, we can import a type that was defined in another file:

/**
 * Returns user's age
 *
 * @param {import ('./user.js').User} user
 * @returns {number}
 */
function getAge(user) {
    //...
}

Variable typing

Sometimes we may want to set a type for a variable. In JsDoc, @type tag is used for this purpose:

/**
 * @type {import ('./user.js').User}
 */
const user = {
    name: "John Doe",
    email: "j.doe@email.com"
}

Now typescript will process the object behind the user variable as a User type that was defined in the user.js file.

Import type from an other package

We can import types from modules as well:

@returns {import("node:child_process").SpawnSyncReturns<Buffer | string | undefined>}

Add typescript

To take an advantage of typescript with JsDoc, we need two things:

  1. Add typescript support to our project
  2. Add // @ts-check comment to the beginning of file

Now, when we run tsc --noEmit command, typescript will check types correctness in all files that have the @ts-check directive.

LSP works fine with this approach, too - you can enjoy hints, autocomplete, error messages and documentation popups right in your text editor (below are screens of Sublime Text with the LSP plugin in action):

JsDoc popup:

LSP popup screenshot

Implict Any type warning:

LSP popup screenshot

Wrong type error:

LSP popup screenshot

Links