all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
blob 82a12906e7a61daf3b2ff7be99dd147164c98aa6 20691 bytes (raw)
name: doc/misc/vtable.texi 	 # note: path name is non-authoritative(*)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
 
\input texinfo @c -*-texinfo-*-
@c %**start of header
@setfilename ../../info/vtable.info
@settitle Variable Pitch Tables
@include docstyle.texi
@c Merge all indexes into a single Index node.
@syncodeindex fn cp
@syncodeindex vr cp
@syncodeindex ky cp
@c %**end of header

@copying
This file documents the GNU vtable.el package.

Copyright @copyright{} 2022--2024 Free Software Foundation, Inc.

@quotation
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3 or
any later version published by the Free Software Foundation; with no
Invariant Sections, with the Front-Cover Texts being ``A GNU Manual,''
and with the Back-Cover Texts as in (a) below.  A copy of the license
is included in the section entitled ``GNU Free Documentation License.''

(a) The FSF's Back-Cover Text is: ``You have the freedom to copy and
modify this GNU manual.''
@end quotation
@end copying

@dircategory Emacs misc features
@direntry
* vtable: (vtable).     Variable Pitch Tables.
@end direntry

@finalout

@titlepage
@title Variable Pitch Tables
@subtitle Columnar Display of Data.

@page
@vskip 0pt plus 1filll
@insertcopying
@end titlepage

@contents

@ifnottex
@node Top
@top vtable

@insertcopying
@end ifnottex

@menu
* Introduction::        Introduction and examples.
* Concepts::            vtable concepts.
* Making A Table::      The main interface function.
* Commands::            vtable commands.
* Interface Functions:: Interface functions.

Appendices
* GNU Free Documentation License::  The license for this documentation.

Indices
* Index::
@end menu

@node Introduction
@chapter Introduction and Tutorial

Most modes that display tabular data in Emacs use
@code{tabulated-list-mode}, but it has some limitations: It assumes
that the text it's displaying is monospaced, which makes it difficult
to mix fonts and images in a single list.  The @dfn{vtable} (``variable
pitch tables'') package tackles this instead.

@code{tabulated-list-mode} is a major mode, and assumes that it
controls the entire buffer.  A vtable doesn't assume that---you can have
a vtable in the middle of other data, or have several vtables in the
same buffer.

Here's just about the simplest vtable that can be created:

@lisp
(make-vtable
 :objects '(("Foo" 1034)
            ("Gazonk" 45)))
@end lisp

By default, vtable uses the @code{vtable} face (which inherits from
the @code{variable-pitch} face), and right-aligns columns that have
only numerical data (and left-aligns the rest).

You'd normally want to name the columns:

@lisp
(make-vtable
 :columns '("Name" "ID")
 :objects '(("Foo" 1034)
            ("Gazonk" 45)))
@end lisp

Clicking on the column names will sort the table based on the data in
each column (which, in this example, corresponds to an element in a
list).

By default, the data is displayed ``as is'', that is, the way
@samp{(format "%s" ...)} would display it, but you can override that.

@lisp
(make-vtable
 :columns '("Name" "ID")
 :objects '(("Foo" 1034)
            ("Gazonk" 45))
 :formatter (lambda (value column &rest _)
              (if (= column 1)
                  (file-size-human-readable value)
                value)))
@end lisp

In this case, that @samp{1034} will be displayed as @samp{1k}---but
will still sort after @samp{45}, because sorting is done on the actual
data, and not the displayed data.

Alternatively, instead of having a general formatter for the table,
you can put the formatter in the column definition:

@lisp
(make-vtable
 :columns '("Name"
            (:name "ID" :formatter file-size-human-readable))
 :objects '(("Foo" 1034)
            ("Gazonk" 45)))
@end lisp

The data doesn't have to be simple lists---you can give any type of
object to vtable, but then you also have to write a function that
returns the data for each column.  For instance, here's a very simple
version of @kbd{M-x list-buffers}:

@lisp
(make-vtable
 :columns '("Name" "Size" "File")
 :objects (buffer-list)
 :actions '("k" kill-buffer
            "RET" display-buffer)
 :getter (lambda (object column vtable)
           (pcase (vtable-column vtable column)
             ("Name" (buffer-name object))
             ("Size" (buffer-size object))
             ("File" (or (buffer-file-name object) "")))))
@end lisp

@var{objects} in this case is a list of buffers.  To get the data to
be displayed, vtable calls the @dfn{getter} function, which is called
for each column of every object, and which should return the data that
will eventually be displayed.

Also note the @dfn{actions}: These are simple commands that will be
called with the object under point.  So hitting @kbd{@key{RET}} on a line
will result in @code{display-buffer} being called with a buffer object
as the parameter.  (You can also supply a keymap to be used, but then
you have to write commands that call @code{vtable-current-object} to
get at the object.)

Note that the actions aren't called with the data displayed in the
buffer---they're called with the original objects.

Finally, here's an example that uses just about all the features:

@lisp
(make-vtable
 :columns `(( :name "Thumb" :width "500px"
              :displayer
              ,(lambda (value max-width table)
                 (propertize "*" 'display
                             (create-image value nil nil
                                           :max-width max-width))))
            (:name "Size" :width 10
                   :formatter file-size-human-readable)
            (:name "Time" :width 10 :primary ascend)
            "Name")
 :objects-function (lambda ()
                     (directory-files "/tmp/" t "\\.jpg\\'"))
 :actions '("RET" find-file)
 :getter (lambda (object column table)
           (pcase (vtable-column table column)
             ("Name" (file-name-nondirectory object))
             ("Thumb" object)
             ("Size" (file-attribute-size (file-attributes object)))
             ("Time" (format-time-string
                      "%F" (file-attribute-modification-time
                            (file-attributes object))))))
 :separator-width 5
 :keymap (define-keymap
           "q" #'kill-buffer))
@end lisp

This vtable implements a simple image browser that displays image
thumbnails (that change sizes dynamically depending on the width of
the column), human-readable file sizes, date and file name.  The
separator width is 5 typical characters wide.  Hitting @kbd{@key{RET}} on a
line will open the image in a new window, and hitting @kbd{q} will
kill a buffer.

@node Concepts
@chapter Concepts

@cindex vtable
A vtable lists data about a number of @dfn{objects}.  Each object can
be a list or a vector, but it can also be anything else.

@cindex getter of a vtable
To get the @dfn{value} for a particular column, the @dfn{getter}
function is called on the object.  If no getter function is defined,
the default is to try to index the object as a sequence.  In any case,
we end up with a value that is then used for sorting.

@cindex formatter of a vtable
This value is then @dfn{formatted} via a @dfn{formatter} function,
which is called with the @dfn{value} as the argument.  The formatter
commonly makes the value more reader friendly.

@cindex displayer of a vtable
Finally, the formatted value is passed to the @dfn{displayer}
function, which is responsible for putting the table face on the
formatted value, and also ensuring that it's not wider than the column
width.  The displayer will commonly truncate too-long strings and
scale image sizes.

All these three transforms, the getter, the formatter and the display
functions, can be defined on a per-column basis, and also on a
per-table basis.  (The per-column transform takes precedence over the
per-table transform.)

User commands that are defined on a table does not work on the
displayed data.  Instead they are called with the original object as
the argument.

@node Making A Table
@chapter Making A Table

@findex make-vtable
The interface function for making (and optionally inserting a table
into a buffer) is @code{make-vtable}.  It returns a table object.

The keyword parameters are described below.

There are many callback interface functions possible in
@code{make-vtable}, and many of them take a @var{object} argument (an
object from the @code{:objects} list), a column index argument (an
integer starting at zero), and a table argument (the object returned
by @code{make-vtable}).

@table @code
@item :objects
This is a list of objects to be displayed.  It should either be a list
of strings (which will then be displayed as a single-column table), or
a list where each element is a sequence containing a mixture of
strings, numbers, and other objects that can be displayed ``simply''.

In the latter case, if @code{:columns} is non-@code{nil} and there's
more elements in the sequence than there is in @code{:columns}, only
the @code{:columns} first elements are displayed.

@item :objects-function
It's often convenient to generate the objects dynamically (for
instance, to make reversion work automatically).  In that case, this
should be a function (which will be called with no arguments), and
should return a value as accepted as an @code{:objects} list.

@item :columns
This is a list where each element is either a string (the column
name), a plist of keyword/values (to make a @code{vtable-column}
object), or a full @code{vtable-column} object.  A
@code{vtable-column} object has the following slots:

@table @code
@item name
The name of the column.

@item width
The width of the column.  This is either a number (the width of that
many @samp{x} characters in the table's face), or a string on the form
@samp{Xe@var{x}}, where @var{x} is a number of @samp{x} characters, or a
string on the form @samp{Xp@var{x}} (denoting a number of pixels), or a
string on the form @samp{X%} (a percentage of the window's width).

@item min-width
This uses the same format as @code{width}, but specifies the minimum
width (and overrides @code{width} if @code{width} is smaller than this.

@item max-width
This uses the same format as @code{width}, but specifies the maximum
width (and overrides @code{width} if @code{width} is larger than this.
@code{min-width}/@code{max-width} can be useful if @code{width} is
given as a percentage of the window width, and you want to ensure that
the column doesn't grow pointlessly large or unreadably narrow.

@item primary
Whether this is the primary column---this will be used for initial
sorting.  This should be either @code{ascend} or @code{descend} to say
in which order the table should be sorted.

@item getter
If present, this function will be called to return the column value.

@defun column-getter object table
It's called with two parameters: the object and the table.
@end defun

@item formatter
If present, this function will be called to format the value.

@defun column-formatter value
It's called with one parameter: the column value.
@end defun

@item displayer
If present, this function will be called to prepare the formatted
value for display.  This function should return a string with the
table face applied, and also limit the width of the string to the
display width.

@defun column-displayer fvalue max-width table
@var{fvalue} is the formatted value; @var{max-width} is the maximum
width (in pixels), and @var{table} is the table.
@end defun

@item align
Should be either @code{right} or @code{left}.
@end table

@item :getter
If given, this is a function that should return the values to use in
the table, and will be called once for each element in the table
(unless overridden by a column getter function).

@defun getter object index table
For a simple object (like a sequence), this function will typically
just return the element corresponding to the column index (zero-based), but the
function can do any computation it wants.  If it's more convenient to
write the function based on column names rather than the column index,
the @code{vtable-column} function can be used to map from index to name.
@end defun

@item :formatter
If present, this is a function that should format the value, and it
will be called on all values in the table (unless overridden by a
column formatter).

@defun formatter value index table
This function is called with three parameters: the value (as returned
by the getter); the column index, and the table.  It can return any
value.

This can be used to (for instance) format numbers in a human-readable
form.
@end defun

@item :displayer
Before displaying an element, it's passed to the displaying function
(if any).

@defun displayer fvalue index max-width table
This is called with four arguments: the formatted value of the element
(as returned by the formatter function); the column index; the display
width (in pixels); and the table.

This function should return a string with the table face applied, and
truncated to the display width.

This can be used to (for instance) change the size of images that are
displayed in the table.
@end defun

@item :use-header-line
If non-@code{nil} (which is the default), display the column names on
the header line.  This is the most common use
case, but if there's other text in the buffer before the table, or
there are several tables in the same buffer, then this should be
@code{nil}.

@item :face
The face to be used.  This defaults to @code{vtable}.  This face
doesn't override the faces in the data, or the faces supplied by the
getter and formatter functions.

@item :row-colors
If present, this should be a list of color names to be used as the
background color on the rows.  If there are fewer colors here than
there are rows, the rows will be repeated.  The most common use
case here is to have alternating background colors on the rows, so
this would usually be a list of two colors.  This can also be a list
of faces to be used.

@item :column-colors
If present, this should be a list of color names to be used as the
background color on the columns.  If there are fewer colors here than
there are columns, the colors will be repeated.  The most common use
case here is to have alternating background colors on the columns, so
this would usually be a list of two colors.  This can also be a list
of faces to be used.  If both @code{:row-colors} and
@code{:column-colors} is present, the colors will be ``blended'' to
produce the final colors in the table.

@item :actions
This uses the same syntax as @code{define-keymap}, but doesn't refer
to commands directly.  Instead each key is bound to a command that
picks out the current object, and then calls the function specified
with that as the argument.

@item :keymap
This is a keymap used on the table.  The commands here are called as
usual, and if they're supposed to work on the object displayed on the
current line, they can use the @code{vtable-current-object} function
(@pxref{Interface Functions}) to determine what that object is.

@item :separator-width
The width of the blank space between columns.

@item :divider-width
@itemx :divider
You can have a divider inserted between the columns.  This can either
be specified by using @code{:divider}, which should be a string to be
displayed between the columns, or @code{:divider-width}, which
specifies the width of the space to be used as the divider.

@item :sort-by
This should be a list of tuples, and specifies how the table is to be
sorted.  Each tuple should consist of an integer (the column index)
and either @code{ascend} or @code{descend}.

The table is first sorted by the first element in this list, and then
the next, until the end is reached.

@item :ellipsis
By default, when shortening displayed values, an ellipsis will be
shown.  If this is @code{nil}, no ellipsis is shown.  (The text to use
as the ellipsis is determined by the @code{truncate-string-ellipsis}
function.)

@findex vtable-insert
@item :insert
By default, @code{make-vtable} will insert the table at point.  If this
is @code{nil}, nothing is inserted, but the vtable object is returned,
and you can insert it later with the @code{vtable-insert} function.
@end table

@code{make-table} returns a @code{vtable} object.  You can access the
slots in that object by using accessor functions that have names based
on the keywords described above.  For instance, to access the face,
use @code{vtable-face}.

@node Commands
@chapter Commands
@cindex vtable commands

When point is placed on a vtable, the following keys are bound:

@table @kbd
@findex vtable-sort-by-current-column
@item S
Sort the table by the current column
(@code{vtable-sort-by-current-column}).  Note that the table is sorted
according to the data returned by the getter function (@pxref{Making A
Table}), not by how it's displayed in the buffer.  Columns that have
only numerical data are sorted as numbers, the rest are sorted as
strings.

@findex vtable-narrow-current-column
@item @{
Make the current column narrower
(@code{vtable-narrow-current-column}).

@findex vtable-widen-current-column
@item @}
Make the current column wider
(@code{vtable-widen-current-column}).

@findex vtable-previous-column
@item M-<left>
Move to the previous column (@code{vtable-previous-column}).

@findex vtable-next-column
@item M-<right>
Move to the next column (@code{vtable-next-column}).

@findex vtable-revert-command
@item g
Regenerate the table (@code{vtable-revert-command}).  This command
mostly makes sense if the table has a @code{:objects-function} that
can fetch new data.
@end table

@node Interface Functions
@chapter Interface Functions

If you need to write a mode based on vtable, you will have to interact
with the table in
various ways---for instance, you'll need to write commands that
updates an object
and then displays the result.  This chapter describes functions for
such interaction.

@defun vtable-current-table
This function returns the table under point.
@end defun

@defun vtable-current-object
This function returns the object on the current line.  (Note that this
is the original object, not the characters displayed in the
buffer.)
@end defun

@defun vtable-current-column
This function returns the column index of the column under point.
@end defun

@defun vtable-goto-table table
Move point to the start of @var{table} and return the position.  If
@var{table} can't be found in the current buffer, don't move point and
return @code{nil}.
@end defun

@defun vtable-goto-object object
Move point to the start of the line where @var{object} is displayed in
the current table and return the position.  If @var{object} can't be found,
don't move point and return @code{nil}.
@end defun

@defun vtable-goto-column index
Move point to the start of the @var{index}th column.  (The first
column is numbered zero.)
@end defun

@defun vtable-beginning-of-table
Move to the beginning of the current table.
@end defun

@defun vtable-end-of-table
Move to the end of the current table.
@end defun

@defun vtable-remove-object table object
Remove @var{object} from @var{table}.  This also updates the displayed
table.
@end defun

@defun vtable-insert-object table object &optional location before
Insert @var{object} into @var{table}.  @var{location} should be an
object in the table, the new object is inserted after this object, or
before it if @var{before} is non-nil.  If @var{location} is nil,
@var{object} is appended to @var{table}, or prepended if @var{before} is
non-nil.

@var{location} can also be an integer, a zero-based index into the
table.  In this case, @var{object} is inserted at that index.  If the
index is out of range, @var{object} is prepended to @var{table} if the
index is too small, or appended if it is too large.  In this case,
@var{before} is ignored.

This also updates the displayed table.
@end defun

@defun vtable-update-object table object &optional old-object
Update @var{object}'s representation in @var{table}.  Optional argument
@var{old-object}, if non-@code{nil}, means to replace @var{old-object}
with @var{object} and redisplay the associated row in the table.  In
either case, if the existing object is not found in the table (being
compared with @code{equal}), signal an error.

This has the same effect as calling @code{vtable-remove-object} and
then @code{vtable-insert-object}, but is more efficient.

Note a limitation: if the table's buffer is not in a visible window, or
if its window has changed width since it was updated, updating the table
is not possible, and an error is signaled.
@end defun

@defun vtable-column table index
Return the column name of the @var{index}th column in @var{table}.
@end defun

@node GNU Free Documentation License
@chapter GNU Free Documentation License
@include doclicense.texi

@node Index
@unnumbered Index
@printindex cp

@bye

debug log:

solving 82a12906e7a ...
found 82a12906e7a in https://yhetil.org/emacs/868r0levw7.fsf@fastmail.fm/
found dd5b70cf32f in https://git.savannah.gnu.org/cgit/emacs.git
preparing index
index prepared:
100644 dd5b70cf32f759612af6f4f77e4154b32cbb84c9	doc/misc/vtable.texi

applying [1/1] https://yhetil.org/emacs/868r0levw7.fsf@fastmail.fm/
diff --git a/doc/misc/vtable.texi b/doc/misc/vtable.texi
index dd5b70cf32f..82a12906e7a 100644

Checking patch doc/misc/vtable.texi...
Applied patch doc/misc/vtable.texi cleanly.

index at:
100644 82a12906e7a61daf3b2ff7be99dd147164c98aa6	doc/misc/vtable.texi

(*) Git path names are given by the tree(s) the blob belongs to.
    Blobs themselves have no identifier aside from the hash of its contents.^

Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.