Make text in Emacs-Lisp-overlay overwritable - emacs

I have file where some parts (lines) are fixed width, and other parts are free text.
The format of the fixed width lines behaves somewhat like a table.
Each line has a certain number of field, each field have a fixed length (in characters).
When editing these lines one should use something similar to overwrite-mode.
I am trying figure out how to solve this in Emacs Lisp.
Here is what I have so far:
(defun test-overlay ()
(interactive)
(let ((ovl (make-overlay 1 5 (current-buffer) t t)))
(overlay-put ovl 'face '(:background "grey50"))
(overlay-put ovl 'intangible t)
))
How can I make the overlay behave like the minor mode overwrite-mode?
That is, the overlay should not expand when text is added at the right edge.
When entering text, the text in the overlay should move to the left, the text at the left edge being chopped off (deleted). Pressing Delete at the right edge should delete characters at the right, moving in spaces at the left edge..

Instead of using overlays, use text properties --- specifically the text property read-only. Set its value to nil for the text you want to be writable, and to non-nil for text you want to be read-only. (There is no read-only overlay property.)
From (elisp) Special Properties:
`read-only'
If a character has the property `read-only', then modifying that
character is not allowed. Any command that would do so gets an
error, `text-read-only'. If the property value is a string, that
string is used as the error message.
Insertion next to a read-only character is an error if inserting
ordinary text there would inherit the `read-only' property due to
stickiness. Thus, you can control permission to insert next to
read-only text by controlling the stickiness. *Note Sticky
Properties::.
Since changing properties counts as modifying the buffer, it is not
possible to remove a `read-only' property unless you know the
special trick: bind `inhibit-read-only' to a non-`nil' value and
then remove the property. *Note Read Only Buffers::.

You need to use the modification-hooks property. That let you do the same kind of things as with after-change-functions and hence specify the exact behavior you're looking for.

Related

Overriding buffer-read-only in a region

I want most of a buffer to be read-only, except for one small region (part of a line).
I first tried something like
(setq buffer-read-only t)
(let ((inhibit-read-only t))
(add-text-properties start end '(read-only nil)))
but apparently buffer-read-only takes precedence over the read-only property.
I now have buffer-read-only set to nil, and set the read-only property to t on everything except the editable region. (Or read-only nil is regarded as a no-op.)
Is there a better way?
EDIT:
A more detailed description of my use case is that I want my buffer to display the output of an asynchronous process. The output is mostly for read-only viewing. However, a small part of a line is editable. This part will become input to the process if it is run again.
There's no simple way to do what you need in Emacs 24 and earlier. I agree with your solution to mark everything with the read-only property except the parts that you want to be editable.
Emacs 25 will have the inhibit-read-only property, which does exactly what you want. It was implemented by larsi on 16 November, and is used by eww.

Emacs Line Height

I am trying to set the line height of text in an Emacs buffer so there is space above and below the letters. From the documentation, I infer that the line-height text property may help me to accomplish this.
There is also a line-spacing variable which I can set like (setq-default line-spacing 0.25). This kind of works, except it does not produce space before text, only after it. I don’t like the way this looks when using modes like show-paren-mode, since it “dips” down:
Undesired current behavior (“hanging”)
Desired behavior mockup (vertically-centered)
I'd like to vertically-center the text.
I have discovered that I can temporarily get the effect I want with the following code:
(add-text-properties (point-min) (point-max)
'(line-spacing 0.25 line-height 1.25))
However, in some modes the properties go away in regions where I start typing. How do I make that top and bottom spacing the default? (Hooks won't work.)
Update
TLDR: I've succumbed to the fact that you can't really reliably achieve this natively with Emacs. You need to patch the font itself to include extra spacing. So, I created this script to take care of that.
Old/Incomplete Answer
TLDR: Add this somewhere in init file:
;; Set the padding between lines
(defvar line-padding 3)
(defun add-line-padding ()
"Add extra padding between lines"
; remove padding overlays if they already exist
(let ((overlays (overlays-at (point-min))))
(while overlays
(let ((overlay (car overlays)))
(if (overlay-get overlay 'is-padding-overlay)
(delete-overlay overlay)))
(setq overlays (cdr overlays))))
; add a new padding overlay
(let ((padding-overlay (make-overlay (point-min) (point-max))))
(overlay-put padding-overlay 'is-padding-overlay t)
(overlay-put padding-overlay 'line-spacing (* .1 line-padding))
(overlay-put padding-overlay 'line-height (+ 1 (* .1 line-padding))))
(setq mark-active nil))
(add-hook 'buffer-list-update-hook 'add-line-padding)
Increase or decrease the line-padding value to your liking.
This answer pretty much just summarizes the information in the above question, answer, and comments, so I suggest reading those first.
I use an overlay instead of text properties because it behaves more nicely when adding new text to the buffer (especially via copy/paste).
The buffer-list-update-hook is used as a means of identifying when a new buffer has been created and thus would need to have the overlay applied.
For performance reasons, to not continuously add overlays, the existing padding overlay is deleted if it aleady existed.
As the doc says, line-height is a text (or an overlay) property. It is not a variable.
Try (setq-default line-spacing 20).
line-spacing is a frame parameter or a buffer-local variable. Its value can be an integer number of pixels or a floating-point number specifying spacing relative to the frame's default line height. The doc says nothing about giving it a list value, such as (32 64).
And if you are using Emacs in terminal mode then none of this applies. As the doc says about that:
On text terminals, the line spacing cannot be altered.
Try "Help => More Manuals => Emacs Lisp Reference" and from there type i text properties RET. This will hopefully clarify the situation. As for your specific request, I don't think there's a simple way to get what you want right now. You might like to M-x report-emacs-bug about the display appearence of the paren-highlighting.

Re-filling entire paragraph automatically with auto-fill-mode?

Motivation: Using the defaults, Auto Fill mode seems not as useful as I might
have hoped: If I insert a sentence in the middle of a paragraph, only the current
line is re-filled. When I insert a sentence, I want the entire paragraph to be re-filled.
Question: How can I set auto-fill-function (or perhaps
normal-auto-fill-function) in my .emacs
file so that the paragraph is re-filled whenever a single line overflows?
I tried setting it to fill-paragraph, but then I cannot insert any spaces at the end of a paragraph (e.g., to add another word).
More details: I primarily use Auto Fill mode in the AUCTeX major mode for LaTeX.
The built-in Emacs documentation for auto-fill-mode states:
When auto-fill-mode is on, the auto-fill-function variable is
non-nil.
The value of normal-auto-fill-function specifies the function to use
for auto-fill-function when turning Auto Fill mode on.
The documentation for the normal-auto-fill-function variable
says that it is the function to use for auto-fill-function if Auto Fill mode is
turned on, and that the initial value is do-auto-fill.
You might like to try refill-mode. But in general, it's just tricky to make such a feature work well. Another approach is to only do the refill as part of the redisplay (i.e. without affecting the buffer's actual content). For that, try setting word-wrap or enabling visual-line-mode.
For LaTeX files you can try (requires AUCTeX)
(add-hook 'LaTeX-mode-hook '(lambda ()
(setq auto-fill-function 'LaTeX-fill-paragraph)))
but use it with caution.

Create small read-only unfocused buffer

I have a problem explaining what I need, and this is why I can't find it (probably), but I'll try my best.
I need one line of text on top of modeline, kind of a footer in the buffer. It is for displaying help, so with-electric-help gets very close to it except that there's an issue with focus (I can move focus back to the original window, but the key bindings will be of the help buffer - not good).
Ideally it would be just a line of text which stays on top of modeline (doesn't scroll with the buffer).
My issues with creating just a separate buffer: I don't know how to find out that the user removed focus from the buffer which was previously showing the "small buffer", so I don't know when to hide it.
The header line sounds like it would do what you want. It's basically the same as the mode line, except almost nothing uses it and it appears at the top of the window.
(setq header-line-format "some text")
or even fancier, you can eval things on the fly and set faces:
(setq header-line-format '(:eval (propertize (format "%d" (buffer-size)) 'face 'modeline-inactive)))

set text properties

I want to copy a text from one buffer to another with text properties. So I have
(with-current-buffer from-buffer
(setq text-to-copy (buffer-substring beg end)))
How can I insert the text-to-copy to another buffer with all text properties? I'm interested especially in 'face' properties.
The function buffer-substring returns a list, for example ("substring" 42 51 (face font-lock-keyword-face) 52 59 (face font-lock-function-name-face))
If I pass this list to (insert text-to-copy) it seems that it ignores text properties
If font-lock-mode is turned on in the target buffer of insertion, the face property will be reset once the fontification kicks in. I think you'll need to either turn off font-lock-mode, or munge the text properties to replace 'face' with 'font-lock-face' before insertion.
The 'insert' function should handle strings that include text-properties, as-is. Since buffer-substring by default will return a string with text-properties if present, '(insert text-to-copy)' should be all you need to do.
If on the other hand you wanted to extract the string without the text-properties, you'd want to be using buffer-substring-no-properties instead
That should work. This is from Emacs 23.1.1:
buffer-substring is a built-in function in `C source code'.
(buffer-substring start end)
Return the contents of part of the current buffer as a string.
The two arguments start and end are character positions;
they can be in either order.
The string returned is multibyte if the buffer is multibyte.
This function copies the text properties of that part of the buffer
into the result string; if you don't want the text properties,
use `buffer-substring-no-properties' instead.
You can use the command describe-text-properties interactively to see what it is you actually got:
describe-text-properties is an interactive compiled Lisp function in
`descr-text.el'.
It is bound to <C-down-mouse-2> <dp>, <menu-bar> <edit> <props> <dp>.
(describe-text-properties pos &optional output-buffer)
Describe widgets, buttons, overlays and text properties at pos.
Interactively, describe them for the character after point.
If optional second argument output-buffer is non-nil,
insert the output into that buffer, and don't initialize or clear it
otherwise.