3

I have the following prompt customization for Eshell:

(setq eshell-prompt-function
      (lambda ()
        (let ((c "#fdd"))
          (let ((bc (lambda (str)
                      (propertize str 'face
                                  `(:foreground "black" :background ,c))))
                (cw (lambda (str)
                      (propertize str 'face
                                  `(:foreground ,c :background "white"))))
                (bw (lambda (str)
                      (propertize str 'face
                                  `(:foreground "black" :background "white")))))
            (concat
             (funcall bc (eshell/pwd))
             (funcall cw "\ue0b0") ; requires Fira Code
             (funcall bw " "))))))

(setq eshell-highlight-prompt nil)

My problem is, that I can reset the prompt colors only, if I add an extra space at the end of the prompt.

How can I reset the colors without adding an extra space?

ceving
  • 1,308
  • 1
  • 14
  • 28

1 Answers1

2

Turn off the "stickiness" of the face property at the end of the prompt:

(setq eshell-prompt-function
      (lambda ()
        (let ((c "#fdd"))
          (let ((bc (lambda (str)
                      (propertize str 'face
                                  `(:foreground "black" :background ,c))))
                (cw (lambda (str)
                      (propertize str 'face
                                  `(:foreground ,c :background "white")
                                  'rear-nonsticky t)))
            (concat
             (funcall bc (eshell/pwd))
             (funcall cw "\ue0b0") ; requires Fira Code
            )))))

(setq eshell-highlight-prompt nil)

The problem you ran into is that most text properties in Emacs "stick" to all later text. More precisely, quoting from the Emacs documentation on text property "stickiness" (emphasis added):

When you do insertion with inheritance, which properties are inherited, and from where, depends on which properties are sticky. Insertion after a character inherits those of its properties that are rear-sticky. Insertion before a character inherits those of its properties that are front-sticky. When both sides offer different sticky values for the same property, the previous character’s value takes precedence.

By default, a text property is rear-sticky but not front-sticky; thus, the default is to inherit all the properties of the preceding character, and nothing from the following character.

You can control the stickiness of various text properties with two specific text properties, front-sticky and rear-nonsticky, and with the variable text-property-default-nonsticky. You can use the variable to specify a different default for a given property. You can use those two text properties to make any specific properties sticky or nonsticky in any particular part of the text.

If a character’s front-sticky property is t, then all its properties are front-sticky. If the front-sticky property is a list, then the sticky properties of the character are those whose names are in the list. For example, if a character has a front-sticky property whose value is (face read-only), then insertion before the character can inherit its face property and its read-only property, but no others.

The rear-nonsticky property works the opposite way. Most properties are rear-sticky by default, so the rear-nonsticky property says which properties are not rear-sticky. If a character’s rear-nonsticky property is t, then none of its properties are rear-sticky. If the rear-nonsticky property is a list, properties are rear-sticky unless their names are in the list.

Interestingly, according to that documentation, normal insertion isn't supposed to inherit properties at all. But for whatever reason (I haven't investigated) eshell seems to be coded to do inheriting insertion. (This is not obvious when using eshell's default prompt highlighting, because that sets the rear-nonsticky property too.)

mtraceur
  • 184
  • 1
  • 10