Giter Site home page Giter Site logo

trevorpogue / topspace Goto Github PK

View Code? Open in Web Editor NEW
72.0 3.0 1.0 205 KB

Recenter line 1 with scrollable upper margin/padding in Emacs

License: GNU General Public License v3.0

Emacs Lisp 100.00%
scrolling center convenience padding margin cursor elisp upper fringe distraction-free

topspace's Introduction

TopSpace

Scroll down & recenter top lines in Emacs.

Coverage Status

[ Installation | Usage | Customization | Extra functions | How it works ]

TopSpace is an Emacs minor mode that lets you display a buffer's first line in the center of a window instead of just at the top. This is done by automatically drawing an upper margin/padding above line 1 as you recenter and scroll it down.

Features

  • Easier on the eyes: Recenter or scroll down top text to a more comfortable eye level for reading, especially when in full-screen or on a large monitor.
  • Easy to use: No new keybindings are required, keep using all your previous scrolling & recentering commands, except now you can also scroll down the first line. It also integrates seamlessly with centered-cursor-mode to keep the cursor centered all the way to the first line.

Installation

Run the following command in Emacs

     M-x package-install [RET] topspace [RET],

then enable TopSpace locally with

     M-x topspace-mode,

or globally with

     M-x global-topspace-mode.

To enable topspace-mode globally on startup, add the following to your Emacs config

(global-topspace-mode 1)

Usage

Just enable and go

No new keybindings are required, keep using all your previous scrolling & recentering commands, except now you can also scroll down the first line.

Customization

(defcustom topspace-active #'topspace-default-active
  "Determine when `topspace-mode' mode is active / has any effect on buffer.
This is useful in particular when `global-topspace-mode' is enabled but you want
`topspace-mode' to be inactive in certain buffers or in any specific
circumstance.  When inactive, `topspace-mode' will still technically be on,
but will be effectively off and have no effect on the buffer.
Note that if `topspace-active' returns non-nil but `topspace-mode' is off,
`topspace-mode' will still be disabled.

With the default value, topspace will only be inactive in child frames.

If non-nil, then always be active.  If nil, never be active.
If set to a predicate function (function that returns a boolean value),
then be active only when that function returns a non-nil value."
  :type '(choice (const :tag "always" t)
                 (const :tag "never" nil)
                 (function :tag "predicate function")))

(defcustom topspace-autocenter-buffers #'topspace-default-autocenter-buffers
  "Center small buffers with top space when first opened or window sizes change.
This is done by automatically calling `topspace-recenter-buffer'
and the positioning can be customized with `topspace-center-position'.
Top space will not be added if the number of text lines in the buffer is larger
than or close to the selected window's height, or if `window-start' is greater
than 1.

With the default value, buffers will not be centered if in a child frame
or if the user has already scrolled or used `recenter' with buffer in the
selected window.

If non-nil, then always autocenter.  If nil, never autocenter.
If set to a predicate function (function that returns a boolean value),
then do auto-centering only when that function returns a non-nil value."
  :group 'topspace
  :type '(choice (const :tag "always" t)
                 (const :tag "never" nil)
                 (function :tag "predicate function")))

(defcustom topspace-center-position 0.4
  "Target position when centering buffers.

Used in `topspace-recenter-buffer' when called without an argument, or when
opening/resizing buffers if `topspace-autocenter-buffers' returns non-nil.

Can be set to a floating-point number, integer, or function that returns a
floating-point number or integer.

If a floating-point number, it represents the position to center buffers as a
ratio of frame height, and can be a value from 0.0 to 1.0 where lower values
center buffers higher up in the screen.

If a positive or negative integer value, buffers will be centered by putting
their center line at a distance of `topspace-center-position' lines away
from the top of the selected window when positive, or from the bottom
of the selected window when negative.
The distance will be in units of lines with height `default-line-height',
and the value should be less than the height of the window.

If a function, the same rules above apply to the function's return value."
  :group 'topspace
  :type '(choice float integer
                 (function :tag "float or integer function")))

(defcustom topspace-empty-line-indicator
  #'topspace-default-empty-line-indicator
  "Text that will appear in each empty topspace line above the top text line.
Can be set to either a constant string or a function that returns a string.

The conditions in which the indicator string is present are also customizable
by setting `topspace-empty-line-indicator' to a function, where the function
returns \"\" (an empty string) under any conditions in which you don't want
the indicator string to be shown.

By default it will show the empty-line bitmap in the left fringe
if `indicate-empty-lines' is non-nil, otherwise nothing.
This is done by adding a 'display property to the string (see
`topspace-default-empty-line-indicator' for more details).
The default bitmap is the one that the `empty-line' logical fringe indicator
maps to in `fringe-indicator-alist'.

You can alternatively show the string text in the body of each top space line by
having `topspace-empty-line-indicator' return a string without the 'display
property added.  If you do this you may be interested in also changing the
string's face like so: (propertize indicator-string 'face 'fringe)."
  :type '(choice 'string (function :tag "String function")))

(defcustom topspace-mode-line " T"
  "Mode line lighter for Topspace.
The value of this variable is a mode line template as in
`mode-line-format'.  See Info Node `(elisp)Mode Line Format' for
more information.  Note that it should contain a _single_ mode
line construct only.
Set this variable to nil to disable the mode line completely."
  :group 'topspace
  :type 'sexp)

(defvar topspace-keymap (make-sparse-keymap)
  "Keymap for Topspace commands.
By default this is left empty for users to set with their own
preferred bindings.")

Extra functions

;;;###autoload
(defun topspace-height ()
  "Return the top space height in lines for current buffer in selected window.
The top space is the empty region in the buffer above the top text line.
The return value is of type float, and is equivalent to
the top space pixel height / `default-line-height'.

If the height does not exist yet, zero will be returned if
`topspace-autocenter-buffers' returns nil, otherwise a value that centers
the buffer will be returned according to `topspace-center-position'.

If the stored height is now invalid, it will first be corrected by
`topspace--correct-height' before being returned.
Valid top space line heights are:
- never negative,
- only positive when `window-start' equals 1,
  `topspace-active' returns non-nil, and `topspace-mode' is enabled,
- not larger than `topspace--window-height' minus `topspace--context-lines'."
...

;;;###autoload
(defun topspace-set-height (&optional total-lines)
  "Set and redraw the top space overlay to have a target height of TOTAL-LINES.
This sets the top space height for the current buffer in the selected window.
Integer or float values are accepted for TOTAL-LINES, and the value is
considered to be in units of `default-line-height'.

If argument TOTAL-LINES is not provided, the top space height will be set to
the value returned by `topspace-height', which can be useful when redrawing a
previously stored top space height in a window after a new buffer is
displayed in it, or when first setting the height to an initial default value
according to `topspace-height'.

If TOTAL-LINES is invalid, it will be corrected by `topspace--correct-height'.
Valid top space line heights are:
- never negative,
- only positive when `window-start' equals 1,
  `topspace-active' returns non-nil, and `topspace-mode' is enabled,
- not larger than `topspace--window-height' minus `topspace--context-lines'."
  (interactive "P")
...

;;;###autoload
(defun topspace-recenter-buffer (&optional position)
  "Add enough top space to center small buffers according to POSITION.
POSITION defaults to `topspace-center-position'.
Top space will not be added if the number of text lines in the buffer is larger
than or close to the selected window's height, or if `window-start' is greater
than 1.

If POSITION is a float, it represents the position to center buffer as a ratio
of frame height, and can be a value from 0.0 to 1.0 where lower values center
the buffer higher up in the screen.

If POSITION is a positive or negative integer value, buffer will be centered
by putting its center line at a distance of `topspace-center-position' lines
away from the top of the selected window when positive, or from the bottom
of the selected window when negative.
The distance will be in units of lines with height `default-line-height',
and the value should be less than the height of the window.

Top space will not be added if the number of text lines in the buffer is larger
than or close to the selected window's height, or if `window-start' is greater
than 1.

Customize `topspace-center-position' to adjust the default centering position.
Customize `topspace-autocenter-buffers' to run this command automatically
after first opening buffers and after window sizes change."
  (interactive)
...

;;;###autoload
(defun topspace-default-active ()
  "Default function that `topspace-active' is set to.
Return nil if the selected window is in a child-frame."
...

;;;###autoload
(defun topspace-default-autocenter-buffers ()
  "Default function that `topspace-autocenter-buffers' is set to.
Return nil if the selected window is in a child-frame or user has scrolled
buffer in selected window."
...

;;;###autoload
(defun topspace-default-empty-line-indicator ()
  "Default function that `topspace-empty-line-indicator' is set to.
Put the empty-line bitmap in fringe if `indicate-empty-lines' is non-nil.
This is done by adding a 'display property to the returned string.
The bitmap used is the one that the `empty-line' logical fringe indicator
maps to in `fringe-indicator-alist'."
...

;;;###autoload
(defun topspace-buffer-was-scrolled-p ()
  "Return t if current buffer has been scrolled in the selected window before.
This is provided since it is used in `topspace-default-autocenter-buffers'.
Scrolling is only recorded if topspace is active in the buffer at the time of
scrolling."
...

How it works

The "upper margin" is created by drawing an overlay before window-start containing newline characters. As you scroll down the first line, more newline characters are added or removed accordingly.

No new keybindings are required as topspace automatically works for any commands or subsequent function calls which use scroll-up, scroll-down, or recenter as the underlying primitives for scrolling. This includes all scrolling commands/functions available in Emacs as far as the author is aware. This is achieved by using advice-add with the scroll-up, scroll-down, and recenter commands so that custom topspace functions are called before or after each time any of these other commands are called (interactively or otherwise).

Fill out the satisfaction survey to help the author know what you would like improved or added.

topspace's People

Contributors

trevorpogue avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

emacsmirror

topspace's Issues

"Top lines" may be unclear

Hi,

FYI, I wasn't sure what this package did until I saw the demo GIF, because I didn't know what "top lines" meant. You may want to explain that differently in the description. :)

Confict with multiple lines in ElDoc

Describe the bug
When ElDoc shows more than 1 line, topspace "jumps" up.

To Reproduce
I'm using Spacemacs and I don't have enough Emacs experience to test this in an isolated environment.

  1. Install Spacemacs
  2. Enable typescript layer
  3. Add topspace to additional packages
  4. Open a typescript (.ts) file. Add console.log("test"). Add some extra lines so it doesnt fit in the window.
  5. Scroll up
  6. Move the cursor to console. It should now show 2 lines in the echo area below
  7. Bug: the content "jumps" back and the topspace above the first line gets smaller/disappears

Expected behavior
Nothing should happen :)

topspace version information

Latest from MELPA

Emacs version

GNU Emacs 28.1 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.33, cairo version 1.17.6)
of 2022-04-04

[Bug] Breaks Shell-mode in Emacs 29 master

Describe the bug

Initialising Emacs with global-topspace-mode breaks Shell-mode in the master branch of Emacs 29.

When you spawn Shell buffers with Global-TopSpace on, the shell prompt fails to get displayed in buffer. If you try to execute any commands, Emacs freezes up and you have to kill it.

I've narrowed TopSpace down as the culprit for this as commenting it out in my init fixes the issue.

To reproduce

  1. Turn on global-topspace-mode in your init.el (I use use-package, and the code I use is:)

    (use-package topspace
        :ensure t
        :config (global-topspace-mode 1)
        )
    
  2. Launch Emacs

  3. Spawn a Shell buffer (M-x shell RET)

  4. Type anything and press Return

  5. Freeze up

Expected behavior

Shell-mode (and Emacs in-turn) to not freeze up. And spawn with the shell prompt.

TopSpace version information

Version: 20220513.1925
Commit: dd7d35b

Emacs version

GNU Emacs 29.0.50 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.33, cairo version 1.17.6) of 2022-05-22

Feature request: Line number 1 in front of first line of text

Is your feature request related to a problem? Please describe.
With line numbers enabled, line number 1 is currently shown at the top of the buffer. This is perfectly workable but it would be nice if it was in front of the actual first line of text.

Describe the solution you'd like
Have line number 1 be in front of the first line of text.

image

feat: customize a `blacklist` of mode where `topspace` should not be activated

Is your feature request related to a problem? Please describe.

Some modes, like telega, org-agenda-mode look really bad with this mode active, which prevents me from using the global-topspace-mode

Describe the solution you'd like
It would be nice if there was a defcustom variable to customize certain modes where the user does not wish this mode to be active.

Local topspace-mode affects other buffers, too

Describe the bug

M-x topspace-mode affects all buffers, not just the local one.

To Reproduce
Steps to reproduce the behavior:

Example:

  1. Open Emacs emacs -Q, install topspace
  2. Visit file1.el with (require 'topspace) in it.
  3. Open other window C-x 3, visiting another file there, file2.el (doesn't have to exist)
  4. Run M-x topspace-mode in one of the splits
  5. scroll both window splits with the mouse

Expected behavior
The window and its buffer where you ran topspace-mode scrolls down; the other doesn't

Actual behavior
Both windows can scroll down with topspace

Screenshots

Edit: I now realize this variable is not buffer-local by default anyway, and also t after the require, so that's irrelevant. Screenshots left here to show that the mode is off in one of the buffers.

The window where topspace-mode is run:
image

The window that shouldn't have been affected still has topspace-active set to t:
image

Emacs version

GNU Emacs 28.0.90 (build 1, aarch64-apple-darwin21.2.0, NS appkit-2113.20 Version 12.1 (Build 21C52))
of 2021-12-28

topspace.el from master

topspace empty lines vs real new lines

Is there a way to visually distinguish the topspace lines from actual leading new lines in the file itself?

Activating indicate-empty-lines only shows the bottom empty lines in the fringe.

does not work for narrowed buffers

When a buffer is narrowed to a region that doesn't include the first line, then it is not possible to scroll the narrowed region down from the top of the buffer.

To Reproduce

  1. open a document
  2. highlight a region of the document not including the first line
  3. execute M-x narrow-to-region
  4. try to scroll down from the top -- not possible.

Emacs version

GNU Emacs 28.2 (build 2, x86_64-w64-mingw32) of 2022-09-13.

text-scale breaks scrolling

Topspace does not behave when changing the text scale with text-scale-set. When you scroll past the top the screen wraps around the point instead of moving it.
Also evil-scroll-* commands misbehave, sometimes the down scroll gets stuck at a certain point and stops moving further, while the up scroll will once again wrap the screen.
The problem occurs after changing the buffer's text-scale and persists even after reverting the change.

To Reproduce

  1. Open Buffer
  2. enable topspace
  3. M-x eval-expression (text-scale-set 2)
  4. scroll past the point
  5. try evil-mode scroll movement

Emacs version

GNU Emacs 28.2 (build 2, x86_64-w64-mingw32) of 2022-09-13.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.