Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Freeze table rows in emacs org mode

Is there a way to freeze rows in org mode, similar to the functionality in i.e. Excel?

I'm trying to freeze a table header so that when I move down the page, the header still shows?

like image 839
Kevin Heffernan Avatar asked Sep 28 '13 17:09

Kevin Heffernan


People also ask

How do you make a table in Org mode?

The easiest way to create a table is to directly type the "|" character at the beginning of a line, or after any amount of white space. This will put you in the first field of an atomic table. Once you've finished editing this cell, you can jump to the next one by pressing TAB .

How do I create a table in Emacs?

To create a text-based table from scratch, type M-x table-insert . This command prompts for the number of table columns, the number of table rows, cell width and cell height.


2 Answers

Two options come to mind.

  1. The easiest (kludgy but flexible) solution is just to simply split your window horizontally and show the same buffer in both windows. Resize your top window to show only the top of your table and you can scroll the other window independently. The columns will line up since it's a shared buffer and you can delete the unneeded window when you're done.

  2. You can rely on the emacs header line (http://www.emacswiki.org/emacs/HeaderLine) to show the first row of the table at the top of your current window when your point is within the boundaries of an org-table. You accomplish this by setting header-line-format like you would the mode line. This is definitely a cleaner option, but is definitely a more involved solution.

Here's a quick and dirty example that should work for you:

(setq-local header-line-format
        (list '(:eval
            (save-excursion
              (org-table-goto-line 1)
              (substring (thing-at-point 'line t) 0 -1)))))

Here are some attempts at doing something similar: https://emacs.stackexchange.com/questions/774/preview-fields-in-org-table/1040#1040

like image 88
ebpa Avatar answered Nov 16 '22 01:11

ebpa


There is now org-table-sticky-header that seems to do exactly what you want: "A minor mode to show the sticky header for org-mode tables".

The relevant emacs configuration file is "org-table-sticky-header.el" and it contents are:

;;; org-table-sticky-header.el --- Sticky header for org-mode tables  -*- lexical-binding: t; -*-

;; Copyright (C) 2017  Junpeng Qiu

;; Author: Junpeng Qiu <[email protected]>
;; Keywords: extensions
;; Version: 0.1.0
;; Package-Requires: ((org "8.2.10") (emacs "24.4"))

;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.

;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with this program.  If not, see <http://www.gnu.org/licenses/>.

;;; Commentary:

;;                      ______________________________

;;                       ORG-TABLE-STIKCY-HEADER-MODE

;;                               Junpeng Qiu
;;                      ______________________________


;; Table of Contents
;; _________________

;; 1 Overview
;; 2 Usage
;; 3 Demo


;; [[file:https://melpa.org/packages/org-table-sticky-header-badge.svg]]

;; A minor mode to show the sticky header for org-mode tables.


;; [[file:https://melpa.org/packages/org-table-sticky-header-badge.svg]]
;; https://melpa.org/#/org-table-sticky-header


;; 1 Overview
;; ==========

;;   Similar to `semantic-stickyfunc-mode', this package uses the header
;;   line to show the table header when it is out of sight.


;; 2 Usage
;; =======

;;   To install manually:
;;   ,----
;;   | (add-to-list 'load-path "/path/to/org-table-sticky-header.el")
;;   `----

;;   `M-x org-table-sticky-header-mode' to enable the minor mode in an
;;   org-mode buffer.

;;   To automatically enable the minor mode in all org-mode buffers, use
;;   ,----
;;   | (add-hook 'org-mode-hook 'org-table-sticky-header-mode)
;;   `----


;; 3 Demo
;; ======

;;   [./screenshots/demo.gif]

;;; Code:

(require 'org)
(require 'org-table)

(defvar org-table-sticky-header--last-win-start -1)
(defvar org-table-sticky-header--old-header-line-format nil)

(defun org-table-sticky-header--is-header-p (line)
(not
(or (string-match "^ *|-" line)
(let ((cells (split-string line "|"))
(ret t))
(catch 'break
(dolist (c cells ret)
(unless (or (string-match "^ *$" c)
(string-match "^ *<[0-9]+> *$" c)
(string-match "^ *<[rcl][0-9]*> *$" c))
(throw 'break nil))))))))

(defun org-table-sticky-header--table-real-begin ()
(save-excursion
(goto-char (org-table-begin))
(while (and (not (eobp))
(not (org-table-sticky-header--is-header-p
(buffer-substring-no-properties
(point-at-bol)
(point-at-eol)))))
(forward-line))
(point)))

(defun org-table-sticky-header-org-table-header-visible-p ()
(save-excursion
(goto-char org-table-sticky-header--last-win-start)
(>= (org-table-sticky-header--table-real-begin) (point))))

(defun org-table-sticky-header--get-line-prefix-width (line)
(let (prefix)
(and (bound-and-true-p org-indent-mode)
(setq prefix (get-text-property 0 'line-prefix line))
(string-width prefix))))

(defun org-table-sticky-header--get-visual-header (text visual-col)
(if (= visual-col 0)
text
(with-temp-buffer
(insert text)
(goto-char (point-min))
(while (> visual-col 0)
(when (string= (get-text-property (point) 'display) "=>")
(setq visual-col (1- visual-col)))
(move-point-visually 1)
(setq visual-col (1- visual-col)))
(buffer-substring (point) (point-at-eol)))))

(defun org-table-sticky-header-get-org-table-header ()
(let ((col (window-hscroll))
visual-header)
(save-excursion
(goto-char org-table-sticky-header--last-win-start)
(if (bobp)
""
(if (org-at-table-p 'any)
(goto-char (org-table-sticky-header--table-real-begin))
(forward-line -1))
(setq visual-header
(org-table-sticky-header--get-visual-header
(buffer-substring (point-at-bol) (point-at-eol))
col))
(remove-text-properties 0
(length visual-header)
'(face nil)
visual-header)
visual-header))))

(defun org-table-sticky-header--fetch-header ()
(if (org-table-sticky-header-org-table-header-visible-p)
(setq header-line-format org-table-sticky-header--old-header-line-format)
;; stole from `semantic-stickyfunc-mode'
(let ((line (org-table-sticky-header-get-org-table-header)))
(setq header-line-format
`(:eval (list
(propertize
" "
'display
'((space :align-to
,(or (org-table-sticky-header--get-line-prefix-width line)
0))))
,line))))))

(defun org-table-sticky-header--scroll-function (win start-pos)
(unless (= org-table-sticky-header--last-win-start start-pos)
(setq org-table-sticky-header--last-win-start start-pos)
(save-match-data
(org-table-sticky-header--fetch-header))))

(defun org-table-sticky-header--insert-delete-column ()
(if org-table-sticky-header-mode
(save-match-data
(org-table-sticky-header--fetch-header))))

(defun org-table-sticky-header--table-move-column (&optional left)
(if org-table-sticky-header-mode
(save-match-data
(org-table-sticky-header--fetch-header))))

;;;###autoload
(define-minor-mode org-table-sticky-header-mode
"Sticky header for org-mode tables."
nil " OTSH" nil
(if org-table-sticky-header-mode
(if (derived-mode-p 'org-mode)
(progn
(setq org-table-sticky-header--old-header-line-format header-line-format)
(add-hook 'window-scroll-functions
'org-table-sticky-header--scroll-function 'append 'local)
(advice-add 'org-table-delete-column :after #'org-table-sticky-header--insert-delete-column)
(advice-add 'org-table-insert-column :after #'org-table-sticky-header--insert-delete-column)
(advice-add 'org-table-move-column :after #'org-table-sticky-header--table-move-column)
(setq org-table-sticky-header--last-win-start (window-start))
(org-table-sticky-header--fetch-header))
(setq org-table-sticky-header-mode nil)
(error "Not in `org-mode'"))
(advice-remove 'org-table-delete-column #'org-table-sticky-header--insert-delete-column)
(advice-remove 'org-table-insert-column #'org-table-sticky-header--insert-delete-column)
(advice-remove 'org-table-move-column #'org-table-sticky-header--table-move-column)
(remove-hook 'window-scroll-functions 'org-table-sticky-header--scroll-function 'local)
(setq header-line-format org-table-sticky-header--old-header-line-format)))

(provide 'org-table-sticky-header)
;;; org-table-sticky-header.el ends here

It's available from:

  • MELPA > http://melpa.org/#/org-table-sticky-header

  • Github > https://github.com/cute-jumper/org-table-sticky-header/

like image 45
Eduardo Mercovich Avatar answered Nov 15 '22 23:11

Eduardo Mercovich