-
Notifications
You must be signed in to change notification settings - Fork 36
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial public release of the MkDocs Awesome Pages Plugin
- Loading branch information
0 parents
commit 7409992
Showing
22 changed files
with
1,462 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
* text=auto eol=lf |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
.idea/ | ||
env/ | ||
dist/ | ||
build/ | ||
__pycache__/ | ||
*.egg-info/ | ||
|
||
!.gitkeep |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
language: python | ||
python: | ||
- 3.5 | ||
- 3.6 | ||
|
||
branches: | ||
only: | ||
- master | ||
- /^v\d+\.\d+(\.\d+)?(-\S*)?$/ # version tags | ||
|
||
script: | ||
- pytest | ||
|
||
deploy: | ||
provider: pypi | ||
distributions: sdist bdist_wheel | ||
user: $PYPI_USER | ||
password: $PYPI_PASSWORD | ||
on: | ||
tags: true | ||
python: 3.6 | ||
|
||
notifications: | ||
email: | ||
on_success: never |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
# Contribution Guidelines | ||
|
||
Thank you for considering to contribute to this project. These guidelines will help you get going with development and outline the most important rules to follow when submitting pull requests for this project. | ||
|
||
<br/> | ||
|
||
## Development | ||
|
||
#### Setup | ||
|
||
##### Prerequisites | ||
|
||
- [Python 3] | ||
- virtualenv | ||
|
||
##### Steps | ||
|
||
1. Clone the (forked) repository | ||
1. Create a virtualenv with `virtualenv env` | ||
1. Activate virtualenv `source env/Scripts/activate` | ||
1. Run `pip install -r requirements.txt` in the project directory | ||
|
||
#### Running Tests | ||
|
||
```bash | ||
pytest | ||
``` | ||
|
||
<br/> | ||
|
||
|
||
## Submitting Changes | ||
|
||
To get changes merged, create a pull request. Here are a few things to pay attention to when doing so: | ||
|
||
#### Commit Messages | ||
|
||
The summary of a commit should be concise and worded in an imperative mood. | ||
...a *what* mood? This should clear things up: *[How to Write a Git Commit Message][git-commit-message]* | ||
|
||
#### Code Style | ||
|
||
Make sure your code follows [PEP-8](https://www.python.org/dev/peps/pep-0008/) and keeps things consistent with the rest of the code. | ||
|
||
#### Tests | ||
|
||
If it makes sense, writing tests for your PRs is always appreciated and will help get them merged. | ||
|
||
[Python 3]: https://www.python.org/ | ||
[virtualenv]: https://virtualenv.pypa.io/ | ||
[git-commit-message]: https://chris.beams.io/posts/git-commit/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# MIT License | ||
|
||
Copyright (c) 2018 Lukas Geiter | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
include README.md | ||
include LICENSE.md |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
# MkDocs Awesome Pages Plugin [![Build Status][travis-status]][travis-link] | ||
|
||
*An MkDocs plugin that simplifies configuring page titles and their order* | ||
|
||
The awesome-pages plugin allows you to customize how your pages show up the navigation of your MkDocs without having to configure the full structure in your `mkdocs.yml`. It extracts the title from your markdown files and gives you detailed control using a small configuration file directly placed in the relevant directory of your documentation. | ||
|
||
> **Note:** This plugin works best without a `pages` entry in your `mkdocs.yml`. Having a `pages` entry is supported, but you might not get the results you expect, especially if your `pages` structure doesn't match the file structure. | ||
<br/> | ||
|
||
## Installation | ||
|
||
> **Note:** This package requires MkDown version 0.17 or higher. | ||
Install the package with pip: | ||
|
||
```yaml | ||
pip install mkdocs-awesome-pages-plugin | ||
``` | ||
|
||
Enable the plugin in your `mkdocs.yml`: | ||
|
||
```yaml | ||
plugins: | ||
- search | ||
- awesome-pages | ||
``` | ||
> **Note:** If you have no `plugins` entry in your config file yet, you'll likely also want to add the `search` plugin. MkDocs enables it by default if there is no `plugins` entry set, but now you have to enable it explicitly. | ||
|
||
More information about plugins in the [MkDocs documentation][mkdocs-plugins] | ||
|
||
<br/> | ||
|
||
## Features | ||
|
||
### Extract Page Titles from Markdown | ||
|
||
The plugin extracts the H1 title (only `#` syntax is supported) from every page and uses it for the title in the navigation. | ||
|
||
### Set Directory Title | ||
|
||
Create a YAML file named `.pages` in a directory and set the `title` to override the title of that directory in the navigation: | ||
|
||
```yaml | ||
title: Page Title | ||
``` | ||
|
||
### Arrange Pages | ||
|
||
Create a YAML file named `.pages` in a directory and set the `arrange` attribute to change the order of how child pages appear in the navigation. This works for actual pages as well as subdirectories. | ||
|
||
```yaml | ||
title: Page Title | ||
arrange: | ||
- page1.md | ||
- page2.md | ||
- subdirectory | ||
``` | ||
|
||
If you only specify *some* pages, they will be positioned at the beginning, followed by the other pages in their original order. | ||
|
||
You may also include a `...` entry at some position to specify where the rest of the pages should be inserted: | ||
|
||
```yaml | ||
arrange: | ||
- introduction.md | ||
- ... | ||
- summary.md | ||
``` | ||
|
||
In this example `introduction.md` is positioned at the beginning, `summary.md` at the end, and any other pages in between. | ||
|
||
<br/> | ||
|
||
## Options | ||
|
||
You may customize the plugin by passing options in `mkdocs.yml`: | ||
|
||
```yaml | ||
plugins: | ||
- awesome-pages: | ||
filename: .index | ||
disable_auto_arrange_index: true | ||
``` | ||
|
||
### `filename` | ||
|
||
Name of the file used to configure pages of a directory. Default is `.pages` | ||
|
||
### `disable_auto_arrange_index` | ||
|
||
Disable the behavior of automatically putting the page with filename `index.*` at the beginning if there is no order specified in `arrange`. Default is `false` | ||
|
||
<br/> | ||
|
||
## Contributing | ||
|
||
From reporting a bug to submitting a pull request: every contribution is appreciated and welcome. | ||
Report bugs, ask questions and request features using [Github issues][github-issues]. | ||
If you want to contribute to the code of this project, please read the [Contribution Guidelines][contributing]. | ||
|
||
[travis-status]: https://travis-ci.org/lukasgeiter/mkdocs-awesome-pages-plugin.svg?branch=master | ||
[travis-link]: https://travis-ci.org/lukasgeiter/mkdocs-awesome-pages-plugin | ||
[mkdocs-plugins]: http://www.mkdocs.org/user-guide/plugins/ | ||
[github-issues]: https://github.com/lukasgeiter/mkdocs-awesome-pages-plugin/issues | ||
[contributing]: CONTRIBUTING.md |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
import os | ||
import warnings | ||
from functools import reduce | ||
from typing import List, Union, Optional, Dict | ||
|
||
from . import markdown | ||
from .page import Page, RootPage | ||
from .pagesfile import PagesFile | ||
|
||
|
||
class Options: | ||
def __init__(self, *, filename: str, disable_auto_arrange_index: bool): | ||
self.filename = filename | ||
self.disable_auto_arrange_index = disable_auto_arrange_index | ||
|
||
|
||
class PageNotFoundError(Exception): | ||
def __init__(self, page: str, context: str = None): | ||
message = 'Page "{page}" not found.' | ||
if context: | ||
message += ' [{context}]' | ||
|
||
super().__init__(message.format(page=page, context=context)) | ||
|
||
|
||
class TitleInRootPagesFileWarning(Warning): | ||
pass | ||
|
||
|
||
class Factory: | ||
|
||
INDEX_PAGE_NAME = 'index' | ||
|
||
def __init__(self, **kwargs): | ||
self.options = Options(**kwargs) | ||
|
||
def create(self, config: List) -> RootPage: | ||
""" Creates a root page containing the whole tree of pages from the mkdocs config """ | ||
children = self._create_pages(config) | ||
|
||
pages_file = self._load_pages_file('') | ||
if pages_file.title is not None: | ||
warnings.warn( | ||
'Using the "title" attribute in the {filename} file of the doc root has no effect' | ||
.format(filename=self.options.filename), | ||
TitleInRootPagesFileWarning) | ||
|
||
children = self.arrange_pages(children, pages_file) | ||
|
||
return RootPage(children) | ||
|
||
def create_page(self, config_entry: Union[Dict, str]) -> Page: | ||
""" Creates a page from an entry in the mkdocs config """ | ||
if isinstance(config_entry, str): | ||
return self._create_leaf_page(None, config_entry) | ||
|
||
# The config dictionary always contains one entry, retrieve it | ||
[title, value] = next(iter(config_entry.items())) | ||
|
||
if isinstance(value, str): | ||
return self._create_leaf_page(title, value) | ||
else: | ||
return self._create_branch_page(title, value) | ||
|
||
def _create_pages(self, config: List) -> List[Page]: | ||
""" Calls create_page for every entry in the config list """ | ||
return [self.create_page(c) for c in config] | ||
|
||
def _create_leaf_page(self, title: Optional[str], path: str) -> Page: | ||
""" Creates a leaf page, a page pointing to an actual markdown file """ | ||
try: | ||
with open(path) as file: | ||
title = markdown.extract_h1(file) | ||
except FileNotFoundError: | ||
pass | ||
|
||
return Page(title, path) | ||
|
||
def _create_branch_page(self, title: str, config_children: list) -> Page: | ||
""" Creates a branch page, a directory page with child pages """ | ||
children = self._create_pages(config_children) | ||
path = self.common_dirname(children) | ||
|
||
pages_file = self._load_pages_file(path) | ||
title = pages_file.title or title | ||
|
||
children = self.arrange_pages(children, pages_file) | ||
|
||
return Page(title, path, children) | ||
|
||
def _load_pages_file(self, path: str): | ||
""" Loads and parses the pages file for a given path """ | ||
try: | ||
if path is None: | ||
raise FileNotFoundError | ||
return PagesFile.load_from(os.path.join(path, self.options.filename)) | ||
except FileNotFoundError: | ||
# Default to empty pages file | ||
return PagesFile() | ||
|
||
def common_dirname(self, children: List[Page]) -> Optional[str]: | ||
""" Determines the common dirname of all given pages """ | ||
if children: | ||
return reduce(self._common_dirname, children, children[0].dirname) | ||
|
||
def _common_dirname(self, path: Optional[str], page: Page) -> Optional[str]: | ||
""" Reduces pages to a common dirname """ | ||
if page and path is not None and page.dirname == path: | ||
return path | ||
|
||
def arrange_pages(self, pages: List[Page], pages_file: PagesFile) -> List[Page]: | ||
""" Sorts the given pages based on the arrange configuration from the pages file """ | ||
pages_by_basename = self._group_pages_by_basename(pages) | ||
arranged_pages = set() | ||
rest_index = None | ||
result = [] | ||
|
||
# Add pages from arrange configuration | ||
for index, path in enumerate(pages_file.arrange): | ||
if path == PagesFile.ARRANGE_REST_TOKEN: | ||
rest_index = index | ||
elif path in pages_by_basename: | ||
matching_pages = pages_by_basename[path] | ||
arranged_pages.update(matching_pages) | ||
result.extend(matching_pages) | ||
else: | ||
raise PageNotFoundError(path, pages_file.path) | ||
|
||
if rest_index is None: | ||
# If no rest token is used in the arrange configuration, add remaining pages at the end | ||
rest_index = len(result) | ||
|
||
# Add remaining pages | ||
for page in pages: | ||
if page in arranged_pages: | ||
# Skip pages that have already been added | ||
continue | ||
|
||
if ( | ||
not pages_file.arrange | ||
and not self.options.disable_auto_arrange_index | ||
and page.basename is not None | ||
and os.path.splitext(page.basename)[0] == self.INDEX_PAGE_NAME | ||
): | ||
# Automatically position index file at the beginning | ||
result.insert(0, page) | ||
else: | ||
result.insert(rest_index, page) | ||
|
||
rest_index += 1 | ||
|
||
return result | ||
|
||
def _group_pages_by_basename(self, pages: List[Page]) -> Dict[str, List[Page]]: | ||
""" Creates a dictionary with mapping basenames to a list of matching pages """ | ||
result = {} | ||
for page in pages: | ||
if page.basename in result: | ||
result[page.basename].append(page) | ||
else: | ||
result[page.basename] = [page] | ||
return result |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import re | ||
from typing import TextIO, Optional | ||
|
||
|
||
def extract_h1(file: TextIO) -> Optional[str]: | ||
for line in file: | ||
match = re.match('#([^#].*)', line) | ||
if match: | ||
return match.group(1).strip() |
Oops, something went wrong.