Inserting number of leading tabs


I’d like to write a plug in that inserts number of leading tabs for each line. It should work as invisibles but I’m not quite sure how to do it. I read Atom flight manual and also the package sections but I’m still not sure how to do it. Please could someone give me a hint.

Many thanks


You want to refer to the API docs. I also suggest looking at some existing packages to get a feel for how to use it.

Basically, there is a global atom object that can be used to subscribe to events (like TextEditor creation), and the TextEditor docs will be the most relevant for you (a text editor is a single open file with all the syntax highlighting, gutter, etc. information). A Gutter goes on the side, like the line numbers or linter dots. I think this is what you want? To display the number of tabs on each line?

Or do you want to actually insert a number of tabs on each line? I’m a little confused now.


Thank you - it’s helpful.
Yes, I want to display it like the line numbers or linter dots.


First, how much JS (NodeJS) experience do you have?

An overview of the package might be

const { CompositeDisposable } = require("atom")

module.exports = {
  activate () {
    console.log("Activating indent count package...")

    this.subscriptions = new CompositeDisposable() // "subscriptions", because it's generally used for event handling.
    this.subscriptions.add(atom.workspace.observeTextEditors(editor => {

      console.log("Adding gutter to ", editor)

        name: "indent-count", // a unique name to identify this gutter with
        priority: 0, // higher == closer to text
        type: "line-number", // a line number like gutter, so we get a string on each line
        class: "indent-count", // CSS class to allow you to style things
        labelFn: (lineData) => getIndentFromEditorAndLineData(editor, lineData)


  deactivate () {
    console.log("Deactivating indent count package...")
    this.subscriptions.dispose() // unsubscribe from events up if the package is disabled (though proper cleaning would remove all the guttters too)

function getIndentFromEditorAndLineData (editor, { bufferRow, softWrapped, maxDigits }) {
  if (softWrapped) return "." // Can do whatever here.

  // We use bufferRow, which is logical one row per newline, but screenRow is actual "physcial" row.displayed
  const line = editor.lineTextForBufferRow(bufferRow)
  const indent = line.match(/^\s*/)[0].length

  return "" + indent

It has a couple of issues as is:

  • The line number gutter seems to be meant to only be used by the actual line number gutter. Adding this one makes all the other stuff like fold arrows also be applied.
  • The numbers are left aligned

I don’t have easy solutions to these problems. It’s technically possible to overwrite Atom’s internal logic when rendering gutters, but that feels like overkill. You could also try adding a marker to every row and decorate it, but I don’t feel that’s a good idea.

@smashwilson You’ve been doing a lot of UI work recently yes? Do you have an opinion? It seems to me that the API could benefit from a gutter type that is like line number, in that it’s contents is a string (or element) derived from a function on the line number and other context, but not get all the other baggage that comes with the line-number type.


That’s basically what the line-number type is intended to be :grimacing: We primarily introduced it for use by the new patch view in atom/github, which doesn’t currently support folding, so I’m guessing that’s why we missed some of this.

Interesting… I would call that a bug.

:point_up: This one should be fixable with CSS, though.


Thank you, your help is much appreciated! :slight_smile:
I’m learning it but I’m a developer for quite some years.


There’s some other stuff like how it doesn’t update until it scrolls out of view. But hopefully it gives you an idea of using the API.