Skip to content

Commit

Permalink
[docs] migrate guides to visidata/guides/*.md (#2296)
Browse files Browse the repository at this point in the history
Co-authored-by: Saul Pwanson <code@saul.pw>
  • Loading branch information
anjakefala and saulpw authored Feb 7, 2024
1 parent 41bbbcc commit b8a8b5b
Show file tree
Hide file tree
Showing 13 changed files with 199 additions and 222 deletions.
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ include visidata/experimental/noahs_tapestry/*.json
include visidata/experimental/noahs_tapestry/*.md
include visidata/experimental/noahs_tapestry/*.ddw
include visidata/experimental/noahs_tapestry/*.sqlite
include visidata/guides/*.md
63 changes: 28 additions & 35 deletions docs/api/guides.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ Open the Guide Index with ``Space open-guide-index`` within VisiData or ``vd -P
Here's an outline for adding a guide, with our writing style preferences:

1. Launch **GuideIndex** and find the ``name`` of the guide.
2. Make a subclass of ``GuideSheet`` in the primary module.
3. Set ``guide_text`` to a multi-line string.
4. Call ``vd.addGuide`` to register the Guide with VisiData.
2. Create a markdown file ``visidata/guides/{name}.md``.
3. Write the guide.


Hello Guide
------------
Expand All @@ -36,39 +36,44 @@ For example: **MacrosSheet**.

::

Step 2. Make a subclass of ``GuideSheet`` in the primary module
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Step 2. Create a markdown file ``visidata/guides/{name}.md``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

In this example, we would create a ``visidata/guides/MacrosSheet.md``.

At the top of the file, optionally place template front matter, using YAML syntax:

::

class MacrosGuide(GuideSheet):
guide_text = '' # str
sheettype = Sheet # Sheet type
---
sheettype: Sheet
---

This front matter will override the default configuration for guides.

- Put the Guide in the Python file
where the bulk of the code for that feature exists, as the final class declaration. In this example,
we added it to ``visidata/macros.py``. If the ``GuideSheet`` class cannot be imported into that file,
create a new file like ``visidata/features/macros_guide.py``.
At the moment, the main configurable option is ``sheettype``. ``sheettype`` is a string for the type of sheet that the guide involves. VisiData uses this to auto-complete command + options patterns (see "stylings of note").

Its default value is ``Sheet`` (aka TableSheet), the base class for every table sheet.

.. note::

- All Guides inherit from ``GuideSheet``.
The vast majority of guides will not need to set the front matter or change the default sheet type. Only set it if command + option patterns are failing to auto-complete.

- Set ``sheettype`` to the type of sheet that the guide involves
- VisiData uses this to auto-complete command + options patterns (see "stylings of note").
- Its default value is ``Sheet`` (aka TableSheet), the base class for every table sheet.
- Feel free to ask us if you are unsure which sheet type to use.
Feel free to ask us if unsure which sheet type to use.


.. autoclass:: visidata.GuideSheet

Step 3. Set ``guide_text`` to a multi-line string
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Step 3. Write the guide
~~~~~~~~~~~~~~~~~~~~~~~

Next, fill out the text for the guide in the ``guide_text`` variable:
Next, fill out the text for the guide:

::

class MacrosGuide(GuideSheet):
guide_text ='''# Macros
---
sheettype: Sheet
---
# Macros
Macros allow you to bind a command sequence to a keystroke or longname, to replay when that
keystroke is pressed or the command is executed by longname.

Expand Down Expand Up @@ -112,17 +117,5 @@ Some stylings of note:

- In general, do not use the second person perspective ("you", "yours") outside of tutorials.

Step 4. Call ``vd.addGuide`` to register the Guide with VisiData
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

At the bottom of the file, add ``vd.addGuide('GuideName', GuideClass)``.

Finish off the example:

::
vd.addGuide('MacrosSheet', MacrosGuide)

``vd.getGuide`` will now be able to locate the guide!

.. autofunction:: visidata.vd.addGuide
.. autofunction:: visidata.vd.getGuide
2 changes: 2 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"visidata.loaders",
"visidata.vendor",
"visidata.tests",
"visidata.guides",
"visidata.ddw",
"visidata.man",
"visidata.themes",
Expand Down Expand Up @@ -71,6 +72,7 @@
package_data={
"visidata.man": ["vd.1", "vd.txt"],
"visidata.ddw": ["input.ddw", "regex.ddw"],
"visidata.guides": ["visidata/*.md"],
"visidata.tests": ["sample.tsv", "benchmark.csv"],
"visidata.desktop": ["visidata.desktop"],
"visidata.experimenta.noahs_tapestry": [
Expand Down
44 changes: 0 additions & 44 deletions visidata/features/xsv_guide.py

This file was deleted.

40 changes: 27 additions & 13 deletions visidata/guide.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import re

from visidata import vd, BaseSheet, Sheet, ItemColumn, Column, VisiData, ENTER, RowColorizer, AttrDict, MissingAttrFormatter
from visidata import wraptext
from visidata import wraptext, Path

guides_list = '''
GuideIndex ("A Guide to VisiData Guides (you are here)")
Expand Down Expand Up @@ -69,7 +69,7 @@
# advanced usage and developers
ThreadsSheet ("Threads past and present")
PyobjSheet ("Inspecting internal Python objects")
DeveloperGuide ("Inspecting internal Python objects")
# appendices
Expand All @@ -79,8 +79,10 @@
vd.guides = {} # name -> guidecls

@VisiData.api
def addGuide(vd, name, guidecls):
vd.guides[name] = guidecls
def addGuide(vd, name):
guideSource = Path(vd.pkg_resources_files('visidata')/f'guides/{name}.md')
if guideSource.exists():
vd.guides[name] = GuideSheet(name, source=guideSource)

@VisiData.api
class GuideIndex(Sheet):
Expand All @@ -100,7 +102,9 @@ def iterload(self):
for line in guides_list.splitlines():
m = re.search(r'(\w+?) \("(.*)"\)', line)
if m:
yield [i] + list(m.groups())
guidename, description = list(m.groups())
vd.addGuide(guidename)
yield [i, guidename, description]
i += 1

def openRow(self, row):
Expand Down Expand Up @@ -156,15 +160,26 @@ class GuideSheet(Sheet):
ItemColumn('guide', 1, width=80, displayer='full'),
]
precious = False
guide_text = ''
sheettype = Sheet

def iterload(self):
self.metadata = AttrDict(sheettype='Sheet')
text = self.source.open(mode='r').read()
winWidth = 78
helper = AttrDict(commands=CommandHelpGetter(self.sheettype),
helper = AttrDict(commands=CommandHelpGetter(globals()[self.metadata.sheettype]),
options=OptionHelpGetter())
guidetext = MissingAttrFormatter().format(self.guide_text, help=helper, vd=vd)
for startingLine, text in enumerate(guidetext.splitlines()):
guidetext = MissingAttrFormatter().format(text, help=helper, vd=vd)

# parsing front matter
sections = guidetext.split('---\n', maxsplit=2)
for section in sections[:-1]:
for config in section.splitlines():
config = config.strip()
if config:
key, val = config.split(': ', maxsplit=1)
self.metadata[key] = val

# parsing guide
for startingLine, text in enumerate(sections[-1].splitlines()):
text = text.strip()
if text:
for i, (L, _) in enumerate(wraptext(str(text), width=winWidth)):
Expand All @@ -173,11 +188,10 @@ def iterload(self):
yield [startingLine+1, text]



@VisiData.api
def getGuide(vd, name): # -> GuideSheet()
if name in vd.guides:
return vd.guides[name]()
return vd.guides[name]
vd.warning(f'no guide named {name}')

BaseSheet.addCommand('', 'open-guide-index', 'vd.push(GuideIndex("VisiData_Guide"))', 'open VisiData guides table of contents')
Expand All @@ -204,4 +218,4 @@ def getCommandInfo(sheet, keys):

vd.optalias('guides', 'preplay', 'open-guide-index')

vd.addGlobals({'GuideSheet':GuideSheet, "CommandHelpGetter": CommandHelpGetter, "OptionHelpGetter": OptionHelpGetter})
vd.addGlobals({"CommandHelpGetter": CommandHelpGetter, "OptionHelpGetter": OptionHelpGetter})
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
from visidata import GuideSheet, vd

class ErrorsGuide(GuideSheet):
guide_text='''# What was that error?
# What was that error?

Status messages include [:warning]warnings[/] and [:error]errors[/].

Expand All @@ -18,9 +15,3 @@ class ErrorsGuide(GuideSheet):
If [:note_type]{vd.options.note_format_exc}[/] or [:error]{vd.options.note_getter_exc}[/] appear inside a cell, it indicates an error happened during calculation, type-conversion, or formatting. When the cursor is on an error cell:

- {help.commands.error_cell}
'''



vd.addGuide('ErrorsSheet', ErrorsGuide)

38 changes: 38 additions & 0 deletions visidata/guides/JsonSheet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Some special features for JSON

## Working with nested data

VisiData uses these conventions to display nested data:

- {{2}} indicates a nested object with 2 keys
- [3] indicates a nested array with 3 elements

[:note_type]Expanding[/] unpacks nested data column-wise, often useful for nested objects:

- {help.commands.expand-col}
- {help.commands.expand-col-depth}
- {help.commands.expand-cols}
- {help.commands.expand-cols-depth}

To revert earlier `expand-` operations:

- {help.commands.contract-col}
- {help.commands.contract-col-depth}
- {help.commands.contract-cols}
- {help.commands.contract-cols-depth}

[:note_type]Unfurling[/] unpacks nested data row-wise, often useful for nested arrays:

- {help.commands.unfurl-col}

Note that `unfurl-col` creates a new sheet with `_unfurled` appended to the name. There is no command to revert an unfurl; instead, quit the unfurled sheet.

For particularly deep or complex nested data, it can be helpful to open an individual cell as a new sheet:

- {help.commands.open-cell}

## Options to control JSON save behavior

- {help.options.json_indent}
- {help.options.json_sort_keys}
- {help.options.json_ensure_ascii}
19 changes: 19 additions & 0 deletions visidata/guides/MacrosSheet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Macros
Macros allow you to bind a command sequence to a keystroke or longname, to replay when that keystroke is pressed or the command is executed by longname.

The basic usage is:
1. {help.commands.macro_record}.
2. Execute a series of commands.
3. `m` again to complete the recording, and prompt for the keystroke or longname to bind it to.

The macro will then be executed everytime the provided keystroke or longname are used. Note: the Alt+keys and the function keys are left unbound; overriding other keys may conflict with existing bindings, now or in the future.

Executing a macro will the series of commands starting on the current row and column on the current sheet.

# The Macros Sheet

- {help.commands.macro_sheet}

- `d` (`delete-row`) to mark macros for deletion
- {help.commands.commit_sheet}
- `Enter` (`open-row`) to open the macro in the current row, and view the series of commands composing it'''
44 changes: 44 additions & 0 deletions visidata/guides/SelectionGuide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Selecting and filtering

Some commands operate only on "selected rows". For instance, a common command to filter is {help.commands.dup_selected}.

Many g-prefixed commands are like this. For example, use {help.commands.edit_cell}, but use {help.commands.setcol_input}. Search for "selected rows" in the [:onclick help-commands-all]commands list[/] or the [:onclick sysopen-help]manpage[/] for a full list.

Rows on the **Frequency Table** or **Pivot Table** reference a group of rows from the source sheet. Selecting a row on those sheets also selects the referenced rows on the underlying source sheet.

Select and unselect rows with these commands:

## One row at a time

- {help.commands.select_row}
- {help.commands.unselect_row}
- {help.commands.stoggle_row}

## All rows at the same time

- {help.commands.select_rows}
- {help.commands.unselect_rows}
- {help.commands.stoggle_rows}

## By matching patterns

- {help.commands.select_col_regex}
- {help.commands.unselect_col_regex}
- {help.commands.select_cols_regex}
- {help.commands.unselect_cols_regex}

- {help.commands.select_equal_cell}
- {help.commands.select_equal_row}

## Select by Python expression

Python expressions can use a column value by the column name, if the
column name is a valid Python identifier (with only letters, digits, and underscores).

- {help.commands.select_expr}
- {help.commands.unselect_expr}

## Options

- {help.options.bulk_select_clear}
- {help.options.some_selected_rows}
Loading

0 comments on commit b8a8b5b

Please sign in to comment.