Skip to content

Commit 624969d

Browse files
authored
🔀 Merge pull request #31 from davep/docs
Add documentation
2 parents 575ec62 + 62daa8b commit 624969d

38 files changed

+873
-80
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,5 @@
66
build/
77
dist/
88
__pycache__
9+
site/
10+
.screenshot_cache/

.images/file-open.png

177 KB
Loading

.images/file-save.png

179 KB
Loading

Makefile

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
lib := textual_fspicker
2-
src := src/
3-
run := rye run
4-
test := rye test
5-
python := $(run) python
6-
lint := rye lint -- --select I
7-
fmt := rye fmt
8-
mypy := $(run) mypy
1+
lib := textual_fspicker
2+
src := src/
3+
examples := docs/examples
4+
run := rye run
5+
test := rye test
6+
python := $(run) python
7+
lint := rye lint -- --select I
8+
fmt := rye fmt
9+
mypy := $(run) mypy
10+
mkdocs := $(run) mkdocs
911

1012
##############################################################################
1113
# Local "interactive testing" of the code.
@@ -40,23 +42,37 @@ resetup: realclean # Recreate the virtual environment from scratch
4042
# Checking/testing/linting/etc.
4143
.PHONY: lint
4244
lint: # Check the code for linting issues
43-
$(lint) $(src)
45+
$(lint) $(src) $(examples)
4446

4547
.PHONY: codestyle
4648
codestyle: # Is the code formatted correctly?
47-
$(fmt) --check $(src)
49+
$(fmt) --check $(src) $(examples)
4850

4951
.PHONY: typecheck
5052
typecheck: # Perform static type checks with mypy
51-
$(mypy) --scripts-are-modules $(src)
53+
$(mypy) --scripts-are-modules $(src) $(examples)
5254

5355
.PHONY: stricttypecheck
5456
stricttypecheck: # Perform a strict static type checks with mypy
55-
$(mypy) --scripts-are-modules --strict $(src)
57+
$(mypy) --scripts-are-modules --strict $(src) $(examples)
5658

5759
.PHONY: checkall
5860
checkall: codestyle lint stricttypecheck # Check all the things
5961

62+
##############################################################################
63+
# Documentation.
64+
.PHONY: docs
65+
docs: # Generate the system documentation
66+
$(mkdocs) build
67+
68+
.PHONY: rtfm
69+
rtfm: # Locally read the library documentation
70+
$(mkdocs) serve
71+
72+
.PHONY: publishdocs
73+
publishdocs: docs # Set up the docs for publishing
74+
$(run) ghp-import --push site
75+
6076
##############################################################################
6177
# Package/publish.
6278
.PHONY: package
@@ -83,11 +99,11 @@ repl: # Start a Python REPL in the venv.
8399

84100
.PHONY: delint
85101
delint: # Fix linting issues.
86-
$(lint) --fix $(src)
102+
$(lint) --fix $(src) $(examples)
87103

88104
.PHONY: pep8ify
89105
pep8ify: # Reformat the code to be as PEP8 as possible.
90-
$(fmt) $(src)
106+
$(fmt) $(src) $(examples)
91107

92108
.PHONY: tidy
93109
tidy: delint pep8ify # Tidy up the code, fixing lint and format issues.

README.md

Lines changed: 13 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
# textual-fspicker
22

3-
![Viewing its own directory](https://raw.githubusercontent.com/davep/textual-fspicker/main/img/textual-fspicker.png)
4-
*An example of `textual-fspicker` being used in a Textual application*
5-
63
## Introduction
74

85
This library provides a simple set of filesystem navigation and picking
9-
dialogs (actually, as of the time of writing, it only provides two, this is
10-
a very early WiP you're seeing). The aim is to provide "ready to go" dialogs
11-
that should also be fairly easy to tailor to your own applications.
6+
dialogs The aim is to provide "ready to go" dialogs that should also be
7+
fairly easy to tailor to your own applications.
8+
9+
![Opening a file](https://raw.githubusercontent.com/davep/textual-fspicker/main/.images/file-open.png)
10+
![Saving a file](https://raw.githubusercontent.com/davep/textual-fspicker/main/.images/file-save.png)
1211

1312
## Installing
1413

@@ -18,33 +17,17 @@ The package can be installed with `pip` or related tools, for example:
1817
$ pip install textual-fspicker
1918
```
2019

21-
## The library
22-
23-
Right at the moment there's just two dialogs available:
20+
## Using the library
2421

25-
- `FileOpen` -- For selecting a file from the filesystem.
26-
- `FileSave` -- For selecting a file for saving in the filesystem.
27-
- `SelectDirectory` -- For selecting a directory from the filesysrem.
28-
29-
You can see them in action in the [demo/test
30-
code](https://github.com/davep/textual-fspicker/blob/main/src/textual_fspicker/__main__.py).
31-
32-
Yes, I know that documentation is lacking right now -- I'm still fleshing
33-
out how this will work and what it will provide -- so the best place to see
34-
how the code can be used is in that demo/test code.
22+
Please see [the main documentation for the
23+
library](https://blog.davep.org/textual-fspicker/) for details on how to use
24+
it.
3525

3626
## TODO
3727

38-
- [ ] Flesh out what's displayed for directory entries
39-
- [ ] Add lots of styling options for directory entries
40-
- [ ] Settle on a final set of default styles for the dialogs
41-
- [X] Add a more file-save-oriented dialog
42-
- [X] Add a directory picking dialog
43-
- [X] Add file filtering (extensions using `Select`)
44-
- [X] Expose the hidden show/hide facility of the navigator in the dialogs
45-
- [ ] Better documentation
46-
- [X] Test on Windows
47-
- [ ] Add custom mtime formatting
48-
- [ ] Add support for showing different times
28+
See [the TODO tag in
29+
issues](https://github.com/davep/textual-fspicker/issues?q=is%3Aissue+is%3Aopen+label%3ATODO)
30+
to see what I'm planning.
31+
4932

5033
[//]: # (README.md ends here)

docs/examples/guide/any_open_file.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from textual import on, work
2+
from textual.app import App, ComposeResult
3+
from textual.widgets import Button, Label
4+
5+
from textual_fspicker import FileOpen
6+
7+
8+
class DefaultFileOpenApp(App[None]):
9+
def compose(self) -> ComposeResult:
10+
yield Button("Press to open a file")
11+
yield Label()
12+
13+
@on(Button.Pressed)
14+
@work
15+
async def open_a_file(self) -> None:
16+
if opened := await self.push_screen_wait(FileOpen(must_exist=False)):
17+
self.query_one(Label).update(str(opened))
18+
19+
20+
if __name__ == "__main__":
21+
DefaultFileOpenApp().run()
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from textual import on, work
2+
from textual.app import App, ComposeResult
3+
from textual.widgets import Button, Label
4+
5+
from textual_fspicker import FileOpen
6+
7+
8+
class BasicFileOpenApp(App[None]):
9+
def compose(self) -> ComposeResult:
10+
yield Button("Press to open a file")
11+
yield Label()
12+
13+
@on(Button.Pressed)
14+
@work
15+
async def open_a_file(self) -> None:
16+
if opened := await self.push_screen_wait(FileOpen()):
17+
self.query_one(Label).update(str(opened))
18+
19+
20+
if __name__ == "__main__":
21+
BasicFileOpenApp().run()
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from textual import on, work
2+
from textual.app import App, ComposeResult
3+
from textual.widgets import Button, Label
4+
5+
from textual_fspicker import FileSave
6+
7+
8+
class BasicFileSaveApp(App[None]):
9+
def compose(self) -> ComposeResult:
10+
yield Button("Press to save a file")
11+
yield Label()
12+
13+
@on(Button.Pressed)
14+
@work
15+
async def save_a_file(self) -> None:
16+
if opened := await self.push_screen_wait(FileSave()):
17+
self.query_one(Label).update(str(opened))
18+
19+
20+
if __name__ == "__main__":
21+
BasicFileSaveApp().run()
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from textual import on, work
2+
from textual.app import App, ComposeResult
3+
from textual.widgets import Button, Label
4+
5+
from textual_fspicker import SelectDirectory
6+
7+
8+
class BasicSelectDirectoryApp(App[None]):
9+
def compose(self) -> ComposeResult:
10+
yield Button("Press to select a directory")
11+
yield Label()
12+
13+
@on(Button.Pressed)
14+
@work
15+
async def pick_a_directory(self) -> None:
16+
if opened := await self.push_screen_wait(SelectDirectory()):
17+
self.query_one(Label).update(str(opened))
18+
19+
20+
if __name__ == "__main__":
21+
BasicSelectDirectoryApp().run()
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from textual import on, work
2+
from textual.app import App, ComposeResult
3+
from textual.widgets import Button, Label
4+
5+
from textual_fspicker import FileOpen
6+
7+
8+
class DefaultFileOpenApp(App[None]):
9+
def compose(self) -> ComposeResult:
10+
yield Button("Press to open a file")
11+
yield Label()
12+
13+
@on(Button.Pressed)
14+
@work
15+
async def open_a_file(self) -> None:
16+
if opened := await self.push_screen_wait(FileOpen(default_file="README.md")):
17+
self.query_one(Label).update(str(opened))
18+
19+
20+
if __name__ == "__main__":
21+
DefaultFileOpenApp().run()
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from textual import on, work
2+
from textual.app import App, ComposeResult
3+
from textual.widgets import Button, Label
4+
5+
from textual_fspicker import FileSave
6+
7+
8+
class DefaultSaveFileApp(App[None]):
9+
def compose(self) -> ComposeResult:
10+
yield Button("Press to save a file")
11+
yield Label()
12+
13+
@on(Button.Pressed)
14+
@work
15+
async def save_a_file(self) -> None:
16+
if opened := await self.push_screen_wait(FileSave(default_file="example.md")):
17+
self.query_one(Label).update(str(opened))
18+
19+
20+
if __name__ == "__main__":
21+
DefaultSaveFileApp().run()

docs/examples/guide/filter_open.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from textual import work
2+
from textual.app import App
3+
from textual.widgets import Label
4+
5+
from textual_fspicker import FileOpen, Filters
6+
7+
8+
class BasicFileOpenApp(App[None]):
9+
CSS = """
10+
FileOpen Dialog {
11+
height: 50%;
12+
}
13+
"""
14+
15+
@work
16+
async def on_mount(self) -> None:
17+
if opened := await self.push_screen_wait(
18+
FileOpen(
19+
filters=Filters(
20+
("Python", lambda p: p.suffix.lower() == ".py"),
21+
("Markdown", lambda p: p.suffix.lower() == ".md"),
22+
("TOML", lambda p: p.suffix.lower() == ".toml"),
23+
("YAML", lambda p: p.suffix.lower() == ".yml"),
24+
("All", lambda _: True),
25+
)
26+
)
27+
):
28+
self.query_one(Label).update(str(opened))
29+
30+
31+
if __name__ == "__main__":
32+
BasicFileOpenApp().run()
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from textual import on, work
2+
from textual.app import App, ComposeResult
3+
from textual.widgets import Button, Label
4+
5+
from textual_fspicker import FileSave
6+
7+
8+
class DefaultSaveFileApp(App[None]):
9+
def compose(self) -> ComposeResult:
10+
yield Button("Press to save a file")
11+
yield Label()
12+
13+
@on(Button.Pressed)
14+
@work
15+
async def save_a_file(self) -> None:
16+
if opened := await self.push_screen_wait(FileSave(can_overwrite=False)):
17+
self.query_one(Label).update(str(opened))
18+
19+
20+
if __name__ == "__main__":
21+
DefaultSaveFileApp().run()

docs/examples/index/open_a_file.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from textual import work
2+
from textual.app import App
3+
4+
from textual_fspicker import FileOpen
5+
6+
7+
class OpenAFileApp(App[None]):
8+
@work
9+
async def on_mount(self) -> None:
10+
await self.push_screen_wait(FileOpen())
11+
12+
13+
if __name__ == "__main__":
14+
OpenAFileApp().run()

docs/examples/index/save_a_file.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from textual import work
2+
from textual.app import App
3+
4+
from textual_fspicker import FileSave
5+
6+
7+
class SaveAFileApp(App[None]):
8+
@work
9+
async def on_mount(self) -> None:
10+
await self.push_screen_wait(FileSave())
11+
12+
13+
if __name__ == "__main__":
14+
SaveAFileApp().run()
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from textual import work
2+
from textual.app import App
3+
4+
from textual_fspicker import SelectDirectory
5+
6+
7+
class SelectADirectoryApp(App[None]):
8+
@work
9+
async def on_mount(self) -> None:
10+
await self.push_screen_wait(SelectDirectory())
11+
12+
13+
if __name__ == "__main__":
14+
SelectADirectoryApp().run()

docs/source/.nojekyll

Whitespace-only changes.

0 commit comments

Comments
 (0)