Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: Add "Writing your own prompt" doc #9841

Merged
merged 6 commits into from
Jun 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions doc_src/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ def get_command_description(path, name):
("interactive", "fish-interactive", "", [author], 1),
("relnotes", "fish-releasenotes", "", [author], 1),
("completions", "fish-completions", "", [author], 1),
("prompt", "fish-prompt-tutorial", "", [author], 1),
(
"fish_for_bash_users",
"fish-for-bash-users",
Expand Down
1 change: 1 addition & 0 deletions doc_src/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ Other help pages
fish_for_bash_users
tutorial
completions
prompt
design
relnotes
contributing
Expand Down
172 changes: 172 additions & 0 deletions doc_src/prompt.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
Writing your own prompt
=======================

.. only:: builder_man

.. warning::
This document uses formatting to show what a prompt would look like. If you are viewing this in the man page,
you probably want to switch to looking at the html version instead. Run ``help custom-prompt`` to view it in a web browser.

Fish ships a number of prompts that you can view with the :doc:`fish_config <cmds/fish_config>` command, and many users have shared their prompts online.
zanchey marked this conversation as resolved.
Show resolved Hide resolved

However, you can also write your own, or adjust an existing prompt. This is a good way to get used to fish's :doc:`scripting language <language>`.

Unlike other shells, fish's prompt is built by running a function - :doc:`fish_prompt <cmds/fish_prompt>`. Or, more specifically, three functions:

- :doc:`fish_prompt <cmds/fish_prompt>`, which is the main prompt function
- :doc:`fish_right_prompt <cmds/fish_right_prompt>`, which is shown on the right side of the terminal.
- :doc:`fish_mode_prompt <cmds/fish_mode_prompt>`, which is shown if :ref:`vi-mode <vi-mode>` is used.

These functions are run, and whatever they print is displayed as the prompt (minus one trailing newline).

Here, we will just be writing a simple fish_prompt.

Our first prompt
----------------

Let's look at a very simple example::

function fish_prompt
echo $PWD '>'
end

This prints the current working directory (:envvar:`PWD`) and a ``>`` symbol to show where the prompt ends. The ``>`` is :ref:`quoted <quotes>` because otherwise it would signify a :ref:`redirection <redirects>`.

Because we've used :doc:`echo <cmds/echo>`, it adds spaces between the two so it ends up looking like (assuming ``_`` is your cursor):

.. role:: white
.. parsed-literal::
:class: highlight

:white:`/home/tutorial >`\ _

Formatting
----------

``echo`` adds spaces between its arguments. If you don't want those, you can use :doc:`string join <cmds/string-join>` like this::

function fish_prompt
string join '' -- $PWD '>'
end

The ``--`` indicates to ``string`` that no options can come after it, in case we extend this with something that can start with a ``-``.

There are other ways to remove the space, including ``echo -s`` and :doc:`printf <cmds/printf>`.

Adding colo(u)r
---------------

This prompt is functional, but a bit boring. We could add some color.

Fortunately, fish offers the :doc:`set_color <cmds/set_color>` command, so you can do::

echo (set_color red)foo

``set_color`` can also handle RGB colors like ``set_color 23b455``, and other formatting options including bold and italics.

So, taking our previous prompt and adding some color::

function fish_prompt
string join '' -- (set_color green) $PWD (set_color normal) '>'
end

A "normal" color tells the terminal to go back to its normal formatting options.

What ``set_color`` does internally is to print an escape sequence that tells the terminal to change color. So if you see something like::

echo \e\[31mfoo

that could just be ``set_color red``.

Shortening the working directory
--------------------------------

This is fine, but our :envvar:`PWD` can be a bit long, and we are typically only interested in the last few directories. We can shorten this with the :doc:`prompt_pwd <cmds/prompt_pwd>` helper that will give us a shortened working directory::

function fish_prompt
string join '' -- (set_color green) (prompt_pwd) (set_color normal) '>'
end

``prompt_pwd`` takes options to control how much to shorten. For instance, if we want to display the last two directories, we'd use ``prompt_pwd --full-length-dirs 2``::

function fish_prompt
string join '' -- (set_color green) (prompt_pwd --full-length-dirs 2) (set_color normal) '>'
end

With a current directory of "/home/tutorial/Music/Lena Raine/Oneknowing", this would print

.. role:: green
.. parsed-literal::
:class: highlight

:green:`~/M/Lena Raine/Oneknowing`>_

Status
------

One important bit of information that every command returns is the :ref:`status <variables-status>`. This is a whole number from 0 to 255, and usually it is used as an error code - 0 if the command returned successfully, or a number from 1 to 255 if not.

It's useful to display this in your prompt, but showing it when it's 0 seems kind of wasteful.

First of all, since every command (except for :doc:`set <cmds/set>`) changes the status, you need to store it for later use as the first thing in your prompt. Use a :ref:`local variable <variables-scope>` so it will be confined to your prompt function::

set -l last_status $status

And after that, you can set a string if it not zero::

# Prompt status only if it's not 0
set -l stat
if test $last_status -ne 0
set stat (set_color red)"[$last_status]"(set_color normal)
end

And to print it, we add it to our ``string join``::

string join '' -- (set_color green) (prompt_pwd) (set_color normal) $stat '>'

If ``$last_status`` was 0, ``$stat`` is empty, and so it will simply disappear.

So our entire prompt is now::

function fish_prompt
set -l last_status $status
# Prompt status only if it's not 0
set -l stat
if test $last_status -ne 0
set stat (set_color red)"[$last_status]"(set_color normal)
end

string join '' -- (set_color green) (prompt_pwd) (set_color normal) $stat '>'
end

And it looks like:

.. role:: green
.. role:: red
.. parsed-literal::
:class: highlight

:green:`~/M/L/Oneknowing`\ :red:`[1]`>_

after we run ``false`` (which returns 1).

Where to go from here?
----------------------

We have now built a simple but working and usable prompt, but of course more can be done.

- Fish offers more helper functions:
- ``prompt_login`` to describe the user/hostname/container or ``prompt_hostname`` to describe just the host
- ``fish_is_root_user`` to help with changing the symbol for root.
- ``fish_vcs_prompt`` to show version control information (or ``fish_git_prompt`` / ``fish_hg_prompt`` / ``fish_svn_prompt`` to limit it to specific systems)
- You can add a right prompt by changing :doc:`fish_right_prompt <cmds/fish_right_prompt>` or a vi-mode prompt by changing :doc:`fish_mode_prompt <cmds/fish_mode_prompt>`.
- Some prompts have interesting or advanced features
- Add the time when the prompt was printed
- Show various integrations like python's venv
- Color the parts differently.

You can look at fish's sample prompts for inspiration. Open up :doc:`fish_config <cmds/fish_config>`, find one you like and pick it. For example::

fish_config prompt show # <- shows all the sample prompts
fish_config prompt choose disco # <- this picks the "disco" prompt for this session
funced fish_prompt # <- opens fish_prompt in your editor, and reloads it once the editor exits
1 change: 1 addition & 0 deletions doc_src/python_docs_theme/static/pydoctheme.css
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,7 @@ div.documentwrapper {
.gray { color: #777 }
.purple { color: #551a8b; font-weight: bold; }
.red { color: #FF0000; }
.green { color: #00FF00; }

/* Color based on the Name.Function (.nf) class from pygments.css. */
.command { color: #005fd7 }
Expand Down
2 changes: 2 additions & 0 deletions share/functions/help.fish
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ function help --description 'Show help for the fish shell'
set fish_help_page faq.html
case fish-for-bash-users
set fish_help_page fish_for_bash_users.html
case custom-prompt
set fish_help_page prompt.html
case $faqpages
set fish_help_page "faq.html#$fish_help_item"
case $for_bash_pages
Expand Down