aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.coveragerc6
-rw-r--r--.gitignore3
-rw-r--r--.pylintrc575
-rw-r--r--.travis.yml44
-rw-r--r--LICENSE83
-rw-r--r--Makefile95
-rw-r--r--Pipfile9
-rw-r--r--Pipfile.lock289
-rw-r--r--README.md307
-rw-r--r--README.rst132
-rw-r--r--docs/Makefile20
-rw-r--r--docs/source/conf.py176
-rw-r--r--docs/source/configuration.rst725
-rw-r--r--docs/source/index.rst23
-rw-r--r--docs/source/usage.rst356
-rwxr-xr-xnncli56
-rw-r--r--nncli/__init__.py4
-rw-r--r--nncli/__main__.py6
-rw-r--r--nncli/clipboard.py (renamed from nnotes_cli/clipboard.py)3
-rw-r--r--nncli/config.py (renamed from nnotes_cli/config.py)28
-rw-r--r--nncli/nextcloud_note.py (renamed from nnotes_cli/nextcloud_note.py)37
-rw-r--r--nncli/nncli.py (renamed from nnotes_cli/nncli.py)42
-rw-r--r--nncli/notes_db.py (renamed from nnotes_cli/notes_db.py)32
-rw-r--r--nncli/temp.py (renamed from nnotes_cli/temp.py)4
-rw-r--r--nncli/user_input.py (renamed from nnotes_cli/user_input.py)5
-rw-r--r--nncli/utils.py (renamed from nnotes_cli/utils.py)31
-rw-r--r--nncli/view_help.py (renamed from nnotes_cli/view_help.py)5
-rw-r--r--nncli/view_log.py (renamed from nnotes_cli/view_log.py)5
-rw-r--r--nncli/view_note.py (renamed from nnotes_cli/view_note.py)4
-rw-r--r--nncli/view_titles.py (renamed from nnotes_cli/view_titles.py)5
-rw-r--r--nnotes_cli/__init__.py17
-rw-r--r--pyproject.toml24
-rw-r--r--pytest.ini2
-rw-r--r--setup.cfg12
-rw-r--r--setup.py64
-rw-r--r--tests/test_config.py30
-rw-r--r--tests/test_nncli.py187
-rw-r--r--tests/test_version.py35
-rw-r--r--tox.ini29
39 files changed, 2687 insertions, 823 deletions
diff --git a/.coveragerc b/.coveragerc
new file mode 100644
index 0000000..579f18d
--- /dev/null
+++ b/.coveragerc
@@ -0,0 +1,6 @@
+[run]
+branch = True
+omit = nncli/__main__.py
+
+[report]
+show_missing = True
diff --git a/.gitignore b/.gitignore
index 85a6fc5..c5e83b8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@ build/
dist/
MANIFEST
*.egg-info/
-nnotes_cli/version.py
.coverage
.pytest_cache/
+docs/build/
+.tox
diff --git a/.pylintrc b/.pylintrc
new file mode 100644
index 0000000..b2edc99
--- /dev/null
+++ b/.pylintrc
@@ -0,0 +1,575 @@
+[MASTER]
+
+# A comma-separated list of package or module names from where C extensions may
+# be loaded. Extensions are loading into the active Python interpreter and may
+# run arbitrary code.
+extension-pkg-whitelist=
+
+# Add files or directories to the blacklist. They should be base names, not
+# paths.
+ignore=CVS .git
+
+# Add files or directories matching the regex patterns to the blacklist. The
+# regex matches against base names, not paths.
+ignore-patterns=
+
+# Python code to execute, usually for sys.path manipulation such as
+# pygtk.require().
+#init-hook=
+
+# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the
+# number of processors available to use.
+jobs=1
+
+# Control the amount of potential inferred values when inferring a single
+# object. This can help the performance when dealing with large functions or
+# complex, nested conditions.
+limit-inference-results=100
+
+# List of plugins (as comma separated values of python modules names) to load,
+# usually to register additional checkers.
+load-plugins=
+
+# Pickle collected data for later comparisons.
+persistent=no
+
+# Specify a configuration file.
+#rcfile=
+
+# When enabled, pylint would attempt to guess common misconfiguration and emit
+# user-friendly hints instead of false-positive error messages.
+suggestion-mode=yes
+
+# Allow loading of arbitrary C extensions. Extensions are imported into the
+# active Python interpreter and may run arbitrary code.
+unsafe-load-any-extension=no
+
+
+[MESSAGES CONTROL]
+
+# Only show warnings with the listed confidence levels. Leave empty to show
+# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED.
+confidence=
+
+# Disable the message, report, category or checker with the given id(s). You
+# can either give multiple identifiers separated by comma (,) or put this
+# option multiple times (only on the command line, not in the configuration
+# file where it should appear only once). You can also use "--disable=all" to
+# disable everything first and then reenable specific checks. For example, if
+# you want to run only the similarities checker, you can use "--disable=all
+# --enable=similarities". If you want to run only the classes checker, but have
+# no Warning level messages displayed, use "--disable=all --enable=classes
+# --disable=W".
+disable=unsubscriptable-object,
+ print-statement,
+ parameter-unpacking,
+ unpacking-in-except,
+ old-raise-syntax,
+ backtick,
+ long-suffix,
+ old-ne-operator,
+ old-octal-literal,
+ import-star-module-level,
+ non-ascii-bytes-literal,
+ raw-checker-failed,
+ bad-inline-option,
+ locally-disabled,
+ locally-enabled,
+ file-ignored,
+ suppressed-message,
+ useless-suppression,
+ deprecated-pragma,
+ use-symbolic-message-instead,
+ apply-builtin,
+ basestring-builtin,
+ buffer-builtin,
+ cmp-builtin,
+ coerce-builtin,
+ execfile-builtin,
+ file-builtin,
+ long-builtin,
+ raw_input-builtin,
+ reduce-builtin,
+ standarderror-builtin,
+ unicode-builtin,
+ xrange-builtin,
+ coerce-method,
+ delslice-method,
+ getslice-method,
+ setslice-method,
+ no-absolute-import,
+ old-division,
+ dict-iter-method,
+ dict-view-method,
+ next-method-called,
+ metaclass-assignment,
+ indexing-exception,
+ raising-string,
+ reload-builtin,
+ oct-method,
+ hex-method,
+ nonzero-method,
+ cmp-method,
+ input-builtin,
+ round-builtin,
+ intern-builtin,
+ unichr-builtin,
+ map-builtin-not-iterating,
+ zip-builtin-not-iterating,
+ range-builtin-not-iterating,
+ filter-builtin-not-iterating,
+ using-cmp-argument,
+ eq-without-hash,
+ div-method,
+ idiv-method,
+ rdiv-method,
+ exception-message-attribute,
+ invalid-str-codec,
+ sys-max-int,
+ bad-python3-import,
+ deprecated-string-function,
+ deprecated-str-translate-call,
+ deprecated-itertools-function,
+ deprecated-types-field,
+ next-method-defined,
+ dict-items-not-iterating,
+ dict-keys-not-iterating,
+ dict-values-not-iterating,
+ deprecated-operator-function,
+ deprecated-urllib-function,
+ xreadlines-attribute,
+ deprecated-sys-function,
+ exception-escape,
+ comprehension-escape
+
+# Enable the message, report, category or checker with the given id(s). You can
+# either give multiple identifier separated by comma (,) or put this option
+# multiple time (only on the command line, not in the configuration file where
+# it should appear only once). See also the "--disable" option for examples.
+enable=c-extension-no-member
+
+
+[REPORTS]
+
+# Python expression which should return a note less than 10 (10 is the highest
+# note). You have access to the variables errors warning, statement which
+# respectively contain the number of errors / warnings messages and the total
+# number of statements analyzed. This is used by the global evaluation report
+# (RP0004).
+evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
+
+# Template used to display messages. This is a python new-style format string
+# used to format the message information. See doc for all details.
+#msg-template=
+
+# Set the output format. Available formats are text, parseable, colorized, json
+# and msvs (visual studio). You can also give a reporter class, e.g.
+# mypackage.mymodule.MyReporterClass.
+output-format=text
+
+# Tells whether to display a full report or only the messages.
+reports=yes
+
+# Activate the evaluation score.
+score=yes
+
+
+[REFACTORING]
+
+# Maximum number of nested blocks for function / method body
+max-nested-blocks=5
+
+# Complete name of functions that never returns. When checking for
+# inconsistent-return-statements if a never returning function is called then
+# it will be considered as an explicit return statement and no message will be
+# printed.
+never-returning-functions=sys.exit
+
+
+[VARIABLES]
+
+# List of additional names supposed to be defined in builtins. Remember that
+# you should avoid to define new builtins when possible.
+additional-builtins=
+
+# Tells whether unused global variables should be treated as a violation.
+allow-global-unused-variables=yes
+
+# List of strings which can identify a callback function by name. A callback
+# name must start or end with one of those strings.
+callbacks=cb_,
+ _cb
+
+# A regular expression matching the name of dummy variables (i.e. expected to
+# not be used).
+dummy-variables-rgx=_$|dummy
+
+# Argument names that match this expression will be ignored. Default to name
+# with leading underscore.
+ignored-argument-names=mock.*
+
+# Tells whether we should check for unused import in __init__ files.
+init-import=no
+
+# List of qualified module names which can have objects that can redefine
+# builtins.
+redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io
+
+
+[LOGGING]
+
+# Logging modules to check that the string format arguments are in logging
+# function parameter format.
+logging-modules=logging
+
+
+[TYPECHECK]
+
+# List of decorators that produce context managers, such as
+# contextlib.contextmanager. Add to this list to register other decorators that
+# produce valid context managers.
+contextmanager-decorators=contextlib.contextmanager, pytest.fixture
+
+# List of members which are set dynamically and missed by pylint inference
+# system, and so shouldn't trigger E1101 when accessed. Python regular
+# expressions are accepted.
+generated-members=REQUEST,
+ acl_users,
+ aq_parent,
+ assert_called_once_with,
+ assert_called_once,
+ call_count,
+ print,
+ call_args_list,
+ assert_any_call,
+ assert_not_called
+
+# Tells whether missing members accessed in mixin class should be ignored. A
+# mixin class is detected if its name ends with "mixin" (case insensitive).
+ignore-mixin-members=yes
+
+# Tells whether to warn about missing members when the owner of the attribute
+# is inferred to be None.
+ignore-none=yes
+
+# This flag controls whether pylint should warn about no-member and similar
+# checks whenever an opaque object is returned when inferring. The inference
+# can return multiple potential results while evaluating a Python object, but
+# some branches might not be evaluated, which results in partial inference. In
+# that case, it might be useful to still emit no-member and other checks for
+# the rest of the inferred objects.
+ignore-on-opaque-inference=yes
+
+# List of class names for which member attributes should not be checked (useful
+# for classes with dynamically set attributes). This supports the use of
+# qualified names.
+ignored-classes=SQLObject,
+ DateTimeField,
+ CharField,
+ ForecastioDataBlock
+
+# List of module names for which member attributes should not be checked
+# (useful for modules/projects where namespaces are manipulated during runtime
+# and thus existing member attributes cannot be deduced by static analysis. It
+# supports qualified module names, as well as Unix pattern matching.
+ignored-modules=
+
+# Show a hint with possible names when a member name was not found. The aspect
+# of finding the hint is based on edit distance.
+missing-member-hint=yes
+
+# The minimum edit distance a name should have in order to be considered a
+# similar match for a missing member name.
+missing-member-hint-distance=1
+
+# The total number of similar names that should be taken in consideration when
+# showing a hint for a missing member.
+missing-member-max-choices=1
+
+
+[MISCELLANEOUS]
+
+# List of note tags to take in consideration, separated by a comma.
+notes=FIXME,
+ XXX,
+ TODO
+
+
+[BASIC]
+
+# Naming style matching correct argument names.
+argument-naming-style=snake_case
+
+# Regular expression matching correct argument names. Overrides argument-
+# naming-style.
+argument-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Naming style matching correct attribute names.
+attr-naming-style=snake_case
+
+# Regular expression matching correct attribute names. Overrides attr-naming-
+# style.
+attr-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Bad variable names which should always be refused, separated by a comma.
+bad-names=foo,
+ bar,
+ baz,
+ toto,
+ tutu,
+ tata
+
+# Naming style matching correct class attribute names.
+class-attribute-naming-style=any
+
+# Regular expression matching correct class attribute names. Overrides class-
+# attribute-naming-style.
+class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
+
+# Naming style matching correct class names.
+class-naming-style=PascalCase
+
+# Regular expression matching correct class names. Overrides class-naming-
+# style.
+class-rgx=[A-Z_][a-zA-Z0-9]+$
+
+# Naming style matching correct constant names.
+const-naming-style=UPPER_CASE
+
+# Regular expression matching correct constant names. Overrides const-naming-
+# style.
+const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
+
+# Minimum line length for functions/classes that require docstrings, shorter
+# ones are exempt.
+docstring-min-length=-1
+
+# Naming style matching correct function names.
+function-naming-style=snake_case
+
+# Regular expression matching correct function names. Overrides function-
+# naming-style.
+function-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Good variable names which should always be accepted, separated by a comma.
+good-names=i,
+ j,
+ k,
+ ex,
+ Run,
+ main,
+ _
+
+# Include a hint for the correct naming format with invalid-name.
+include-naming-hint=no
+
+# Naming style matching correct inline iteration names.
+inlinevar-naming-style=any
+
+# Regular expression matching correct inline iteration names. Overrides
+# inlinevar-naming-style.
+inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
+
+# Naming style matching correct method names.
+method-naming-style=snake_case
+
+# Regular expression matching correct method names. Overrides method-naming-
+# style.
+method-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Naming style matching correct module names.
+module-naming-style=snake_case
+
+# Regular expression matching correct module names. Overrides module-naming-
+# style.
+module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
+
+# Colon-delimited sets of names that determine each other's naming style when
+# the name regexes allow several styles.
+name-group=
+
+# Regular expression which should only match function or class names that do
+# not require a docstring.
+no-docstring-rgx=__.*__
+
+# List of decorators that produce properties, such as abc.abstractproperty. Add
+# to this list to register other decorators that produce valid properties.
+# These decorators are taken in consideration only for invalid-name.
+property-classes=abc.abstractproperty
+
+# Naming style matching correct variable names.
+variable-naming-style=snake_case
+
+# Regular expression matching correct variable names. Overrides variable-
+# naming-style.
+variable-rgx=[a-z_][a-z0-9_]{2,30}$
+
+
+[FORMAT]
+
+# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
+expected-line-ending-format=
+
+# Regexp for a line that is allowed to be longer than the limit.
+ignore-long-lines=^\s*(# )?<?https?://\S+>?$
+
+# Number of spaces of indent required inside a hanging or continued line.
+indent-after-paren=8
+
+# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
+# tab).
+indent-string=' '
+
+# Maximum number of characters on a single line.
+max-line-length=80
+
+# Maximum number of lines in a module.
+max-module-lines=1000
+
+# List of optional constructs for which whitespace checking is disabled. `dict-
+# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
+# `trailing-comma` allows a space between comma and closing bracket: (a, ).
+# `empty-line` allows space-only lines.
+no-space-check=trailing-comma,
+ dict-separator
+
+# Allow the body of a class to be on the same line as the declaration if body
+# contains single statement.
+single-line-class-stmt=no
+
+# Allow the body of an if to be on the same line as the test if there is no
+# else.
+single-line-if-stmt=no
+
+
+[SPELLING]
+
+# Limits count of emitted suggestions for spelling mistakes.
+max-spelling-suggestions=4
+
+# Spelling dictionary name. Available dictionaries: none. To make it working
+# install python-enchant package..
+spelling-dict=
+
+# List of comma separated words that should not be checked.
+spelling-ignore-words=
+
+# A path to a file that contains private dictionary; one word per line.
+spelling-private-dict-file=
+
+# Tells whether to store unknown words to indicated private dictionary in
+# --spelling-private-dict-file option instead of raising a message.
+spelling-store-unknown-words=no
+
+
+[SIMILARITIES]
+
+# Ignore comments when computing similarities.
+ignore-comments=yes
+
+# Ignore docstrings when computing similarities.
+ignore-docstrings=yes
+
+# Ignore imports when computing similarities.
+ignore-imports=no
+
+# Minimum lines number of a similarity.
+min-similarity-lines=4
+
+
+[DESIGN]
+
+# Maximum number of arguments for function / method.
+max-args=5
+
+# Maximum number of attributes for a class (see R0902).
+max-attributes=7
+
+# Maximum number of boolean expressions in an if statement.
+max-bool-expr=5
+
+# Maximum number of branch for function / method body.
+max-branches=20
+
+# Maximum number of locals for function / method body.
+max-locals=15
+
+# Maximum number of parents for a class (see R0901).
+max-parents=7
+
+# Maximum number of public methods for a class (see R0904).
+max-public-methods=20
+
+# Maximum number of return / yield for function / method body.
+max-returns=6
+
+# Maximum number of statements in function / method body.
+max-statements=50
+
+# Minimum number of public methods for a class (see R0903).
+min-public-methods=2
+
+
+[CLASSES]
+
+# List of method names used to declare (i.e. assign) instance attributes.
+defining-attr-methods=__init__,
+ __new__,
+ setUp
+
+# List of member names, which should be excluded from the protected access
+# warning.
+exclude-protected=_asdict,
+ _fields,
+ _replace,
+ _source,
+ _make
+
+# List of valid names for the first argument in a class method.
+valid-classmethod-first-arg=cls
+
+# List of valid names for the first argument in a metaclass class method.
+valid-metaclass-classmethod-first-arg=mcs
+
+
+[IMPORTS]
+
+# Allow wildcard imports from modules that define __all__.
+allow-wildcard-with-all=no
+
+# Analyse import fallback blocks. This can be used to support both Python 2 and
+# 3 compatible code, which means that the block might have code that exists
+# only in one or another interpreter, leading to false positives when analysed.
+analyse-fallback-blocks=no
+
+# Deprecated modules which should not be used, separated by a comma.
+deprecated-modules=regsub,
+ TERMIOS,
+ Bastion,
+ rexec
+
+# Create a graph of external dependencies in the given file (report RP0402 must
+# not be disabled).
+ext-import-graph=
+
+# Create a graph of every (i.e. internal and external) dependencies in the
+# given file (report RP0402 must not be disabled).
+import-graph=
+
+# Create a graph of internal dependencies in the given file (report RP0402 must
+# not be disabled).
+int-import-graph=
+
+# Force import order to recognize a module as part of the standard
+# compatibility libraries.
+known-standard-library=
+
+# Force import order to recognize a module as part of a third party library.
+known-third-party=enchant
+
+
+[EXCEPTIONS]
+
+# Exceptions that will emit a warning when being caught. Defaults to
+# "Exception".
+overgeneral-exceptions=Exception
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..d2ae20f
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,44 @@
+# https://travis-ci.org/djmoch/nncli
+language: python
+
+matrix:
+ fast_finish: true
+
+.mixins:
+- &xenial-mixin
+ dist: xenial
+ sudo: true
+ addons:
+ apt:
+ packages:
+ - libgnutls-dev
+
+env:
+ - PIPENV_HIDE_EMOJIS=1 PIPENV_NO_INHERIT=1
+
+install:
+ - pip install -U pip pipenv python-coveralls
+ - make test-install
+
+jobs:
+ include:
+ - stage: test
+ script: make test
+ python: 3.4
+ - stage: test
+ script: make test
+ python: 3.5
+ - stage: test
+ script: make test
+ python: 3.6
+ - stage: test
+ script: make test
+ <<: *xenial-mixin
+ python: 3.7
+ # - stage: lint
+ # script: make lint
+ # python: 3.6
+ - stage: coverage
+ script: make coverage
+ after_success: coveralls
+ python: 3.5
diff --git a/LICENSE b/LICENSE
index 545ffc5..820f037 100644
--- a/LICENSE
+++ b/LICENSE
@@ -21,3 +21,86 @@ 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.
+-------------------------------------------------------------------------------
+
+Portions of this software are adapted from sncli by Eric Davis:
+
+** The MIT License **
+
+Copyright (c) 2014 Eric Davis (edavis@insanum.com)
+
+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.
+
+Dude... just buy me a beer. :-)
+
+-------------------------------------------------------------------------------
+
+Portions of nextcloud_note.py are adapted from simplenote.py by Daniel
+Schauenberg:
+
+Copyright (c) 2011 Daniel Schauenberg
+
+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.
+
+-------------------------------------------------------------------------------
+
+Portions of notes_db and utils modules are adapted from the
+corresponding module in nvpy by Charl P. Botha:
+
+Copyright (c) 2012, Charl P. Botha
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the <organization> nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL CHARL P. BOTHA BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..f6c3472
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,95 @@
+.PHONY: clean clean-test clean-pyc clean-build help lint coverage coverage-html release dist install run debug docs
+.DEFAULT_GOAL := help
+
+define BROWSER_PYSCRIPT
+import os, webbrowser, sys
+
+try:
+ from urllib import pathname2url
+except:
+ from urllib.request import pathname2url
+
+webbrowser.open("file://" + pathname2url(os.path.abspath(sys.argv[1])))
+endef
+export BROWSER_PYSCRIPT
+
+define PRINT_HELP_PYSCRIPT
+import re, sys
+
+for line in sys.stdin:
+ match = re.match(r'^([a-zA-Z_-]+):.*?## (.*)$$', line)
+ if match:
+ target, help = match.groups()
+ print("%-20s %s" % (target, help))
+endef
+export PRINT_HELP_PYSCRIPT
+
+BROWSER := python -c "$$BROWSER_PYSCRIPT"
+PIPENV := pipenv
+PIPRUN := $(PIPENV) run
+PIPINST := $(PIPENV) --bare install --dev
+
+help:
+ @python -c "$$PRINT_HELP_PYSCRIPT" < $(MAKEFILE_LIST)
+
+clean: clean-build clean-pyc clean-test ## remove all build, test, coverage and Python artifacts
+ make -C docs clean
+
+clean-build: ## remove build artifacts
+ rm -fr build/
+ rm -fr dist/
+ rm -fr .eggs/
+ find . -name '*.egg-info' -exec rm -fr {} +
+ find . -name '*.egg' -exec rm -f {} +
+
+clean-pyc: ## remove Python file artifacts
+ find . -name '*.pyc' -exec rm -f {} +
+ find . -name '*.pyo' -exec rm -f {} +
+ find . -name '*~' -exec rm -f {} +
+ find . -name '__pycache__' -exec rm -fr {} +
+ $(PIPRUN) pip uninstall -y nncli
+
+clean-test: ## remove test and coverage artifacts
+ rm -f .coverage
+ rm -fr htmlcov/
+ rm -fr .pytest_cache
+ rm -fr .tox
+
+lint: ## check style with pylint
+ $(PIPRUN) pylint nncli tests --disable=parse-error
+
+test: ## run tests quickly with the default Python
+ $(PIPRUN) python -m pytest
+
+test-all: ## run tests on every Python version with tox
+ $(PIPRUN) tox
+
+test-install: ## install dependenices from Pipfile (for tox / CI builds)
+ $(PIPINST)
+
+coverage: ## check code coverage quickly with the default Python
+ $(PIPRUN) python -m pytest --cov=nncli
+
+coverage-html: coverage ## generate an HTML report and open in browser
+ $(PIPRUN) coverage html
+ $(BROWSER) htmlcov/index.html
+
+release: dist ## package and upload a release
+ $(PIPRUN) flit publish
+
+dist: ## builds source and wheel package
+ $(PIPRUN) flit build
+ ls -l dist
+
+docs: ## builds the sphinx documentation and opens in the browser
+ make -C docs html
+ $(BROWSER) docs/build/html/index.html
+
+install: ## install the package to the active Python's site-packages
+ $(PIPRUN) flit install --deps=none
+
+run: ## run the package from site-packages
+ $(PIPRUN) python -m nncli $(cmd)
+
+debug: install ## debug the package from site packages
+ $(PIPRUN) pudb3 $$($(PIPRUN) which nncli) $(cmd)
diff --git a/Pipfile b/Pipfile
index 3f88c39..34b7a5e 100644
--- a/Pipfile
+++ b/Pipfile
@@ -7,8 +7,6 @@ name = "pypi"
appdirs = "*"
requests = "*"
urwid = "*"
-setuptools = "*"
-setuptools-scm = "*"
[dev-packages]
pytest = "*"
@@ -17,3 +15,10 @@ pytest-mock = "*"
pytest-runner = "*"
pylint = "*"
pudb = "*"
+sphinx = "*"
+flit = "*"
+setuptools = "*"
+mock = "*"
+tox = "*"
+pathlib2 = {version = "*", markers = "python_version < '3.5'"}
+scandir = {version = "*", markers = "python_version < '3.5'"}
diff --git a/Pipfile.lock b/Pipfile.lock
index 8525be7..a1d93f9 100644
--- a/Pipfile.lock
+++ b/Pipfile.lock
@@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
- "sha256": "b4bc66838172733ffa35a5998d87982699b21d67eccdb8d913fffd8c7dcd101a"
+ "sha256": "3dd4d429a27a82ab0f5daa11fb974392ab9f45ac6b20647762d79a1c4ab1bd55"
},
"pipfile-spec": 6,
"requires": {},
@@ -51,20 +51,12 @@
"index": "pypi",
"version": "==2.19.1"
},
- "setuptools-scm": {
- "hashes": [
- "sha256:1191f2a136b5e86f7ca8ab00a97ef7aef997131f1f6d4971be69a1ef387d8b40",
- "sha256:cc6953d224a22f10e933fa2f55c95979317c55259016adcf93310ba2997febfa"
- ],
- "index": "pypi",
- "version": "==3.1.0"
- },
"urllib3": {
"hashes": [
"sha256:a68ac5e15e76e7e5dd2b8f94007233e01effe3e50e8daddf69acfd81cb686baf",
"sha256:b5725a0bd4ba422ab0e66e89e030c806576753ea3ee08554382c14e685d117b5"
],
- "markers": "python_version != '3.1.*' and python_version != '3.3.*' and python_version >= '2.6' and python_version != '3.0.*' and python_version != '3.2.*' and python_version < '4'",
+ "markers": "python_version != '3.1.*' and python_version != '3.3.*' and python_version < '4' and python_version != '3.0.*' and python_version != '3.2.*' and python_version >= '2.6'",
"version": "==1.23"
},
"urwid": {
@@ -76,6 +68,13 @@
}
},
"develop": {
+ "alabaster": {
+ "hashes": [
+ "sha256:674bb3bab080f598371f4443c5008cbfeb1a5e622dd312395d2d82af2c54c456",
+ "sha256:b63b1f4dc77c074d386752ec4a8a7517600f6c0db8cd42980cae17ab7b3275d7"
+ ],
+ "version": "==0.7.11"
+ },
"astroid": {
"hashes": [
"sha256:292fa429e69d60e4161e7612cb7cc8fa3609e2e309f80c224d93a76d5e7b58be",
@@ -85,18 +84,39 @@
},
"atomicwrites": {
"hashes": [
- "sha256:6b5282987b21cd79151f51caccead7a09d0a32e89c568bd9e3c4aaa7bbdf3f3a",
- "sha256:e16334d50fe0f90919ef7339c24b9b62e6abaa78cd2d226f3d94eb067eb89043"
+ "sha256:0312ad34fcad8fac3704d441f7b317e50af620823353ec657a53e981f92920c0",
+ "sha256:ec9ae8adaae229e4f8446952d204a3e4b5fdd2d099f9be3aaf556120135fb3ee"
],
- "markers": "python_version != '3.2.*' and python_version >= '2.7' and python_version != '3.1.*' and python_version != '3.3.*' and python_version != '3.0.*'",
- "version": "==1.2.0"
+ "markers": "python_version != '3.1.*' and python_version >= '2.7' and python_version != '3.0.*' and python_version != '3.2.*' and python_version != '3.3.*'",
+ "version": "==1.2.1"
},
"attrs": {
"hashes": [
- "sha256:4b90b09eeeb9b88c35bc642cbac057e45a5fd85367b985bd2809c62b7b939265",
- "sha256:e0d0eb91441a3b53dab4d9b743eafc1ac44476296a2053b6ca3af0b139faf87b"
+ "sha256:10cbf6e27dbce8c30807caf056c8eb50917e0eaafe86347671b57254006c3e69",
+ "sha256:ca4be454458f9dec299268d472aaa5a11f67a4ff70093396e1ceae9c76cf4bbb"
+ ],
+ "version": "==18.2.0"
+ },
+ "babel": {
+ "hashes": [
+ "sha256:6778d85147d5d85345c14a26aada5e478ab04e39b078b0745ee6870c2b5cf669",
+ "sha256:8cba50f48c529ca3fa18cf81fa9403be176d374ac4d60738b839122dfaaa3d23"
+ ],
+ "version": "==2.6.0"
+ },
+ "certifi": {
+ "hashes": [
+ "sha256:376690d6f16d32f9d1fe8932551d80b23e9d393a8578c5633a2ed39a64861638",
+ "sha256:456048c7e371c089d0a77a5212fb37a2c2dce1e24146e3b7e0261736aaeaa22a"
+ ],
+ "version": "==2018.8.24"
+ },
+ "chardet": {
+ "hashes": [
+ "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
+ "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
],
- "version": "==18.1.0"
+ "version": "==3.0.4"
},
"coverage": {
"hashes": [
@@ -132,18 +152,56 @@
"sha256:e05cb4d9aad6233d67e0541caa7e511fa4047ed7750ec2510d466e806e0255d6",
"sha256:f3f501f345f24383c0000395b26b726e46758b71393267aeae0bd36f8b3ade80"
],
- "markers": "python_version < '4' and python_version != '3.2.*' and python_version != '3.0.*' and python_version != '3.1.*' and python_version >= '2.6'",
+ "markers": "python_version >= '2.6' and python_version != '3.1.*' and python_version != '3.0.*' and python_version != '3.2.*' and python_version < '4'",
"version": "==4.5.1"
},
+ "docutils": {
+ "hashes": [
+ "sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6",
+ "sha256:51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274",
+ "sha256:7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6"
+ ],
+ "version": "==0.14"
+ },
+ "flit": {
+ "hashes": [
+ "sha256:178e6865185b1802aa3b1944f4957d2c83fc56294dc8047d2c4722131f696e61",
+ "sha256:da823d4acae9bda42dcc0c7ab1d9be475a8a47aae5fd6dde63841d9f430ccb2f"
+ ],
+ "index": "pypi",
+ "version": "==1.1"
+ },
+ "idna": {
+ "hashes": [
+ "sha256:156a6814fb5ac1fc6850fb002e0852d56c0c8d2531923a51032d1b70760e186e",
+ "sha256:684a38a6f903c1d71d6d5fac066b58d7768af4de2b832e426ec79c30daa94a16"
+ ],
+ "version": "==2.7"
+ },
+ "imagesize": {
+ "hashes": [
+ "sha256:3f349de3eb99145973fefb7dbe38554414e5c30abd0c8e4b970a7c9d09f3a1d8",
+ "sha256:f3832918bc3c66617f92e35f5d70729187676313caa60c187eb0f28b8fe5e3b5"
+ ],
+ "markers": "python_version != '3.1.*' and python_version >= '2.7' and python_version != '3.0.*' and python_version != '3.2.*' and python_version != '3.3.*'",
+ "version": "==1.1.0"
+ },
"isort": {
"hashes": [
"sha256:1153601da39a25b14ddc54955dbbacbb6b2d19135386699e2ad58517953b34af",
"sha256:b9c40e9750f3d77e6e4d441d8b0266cf555e7cdabdcff33c4fd06366ca761ef8",
"sha256:ec9ef8f4a9bc6f71eec99e1806bfa2de401650d996c59330782b89a5555c1497"
],
- "markers": "python_version >= '2.7' and python_version != '3.3.*' and python_version != '3.2.*' and python_version != '3.0.*' and python_version != '3.1.*'",
+ "markers": "python_version != '3.1.*' and python_version >= '2.7' and python_version != '3.0.*' and python_version != '3.2.*' and python_version != '3.3.*'",
"version": "==4.3.4"
},
+ "jinja2": {
+ "hashes": [
+ "sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd",
+ "sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4"
+ ],
+ "version": "==2.10"
+ },
"lazy-object-proxy": {
"hashes": [
"sha256:0ce34342b419bd8f018e6666bfef729aec3edf62345a53b537a4dcc115746a33",
@@ -178,6 +236,12 @@
],
"version": "==1.3.1"
},
+ "markupsafe": {
+ "hashes": [
+ "sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665"
+ ],
+ "version": "==1.0"
+ },
"mccabe": {
"hashes": [
"sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42",
@@ -185,6 +249,14 @@
],
"version": "==0.6.1"
},
+ "mock": {
+ "hashes": [
+ "sha256:5ce3c71c5545b472da17b72268978914d0252980348636840bd34a00b5cc96c1",
+ "sha256:b158b6df76edd239b8208d481dc46b6afd45a846b7812ff0ce58971cf5bc8bba"
+ ],
+ "index": "pypi",
+ "version": "==2.0.0"
+ },
"more-itertools": {
"hashes": [
"sha256:c187a73da93e7a8acc0001572aebc7e3c69daf7bf6881a2cea10650bd4420092",
@@ -193,12 +265,35 @@
],
"version": "==4.3.0"
},
+ "packaging": {
+ "hashes": [
+ "sha256:e9215d2d2535d3ae866c3d6efc77d5b24a0192cce0ff20e42896cc0664f889c0",
+ "sha256:f019b770dd64e585a99714f1fd5e01c7a8f11b45635aa953fd41c689a657375b"
+ ],
+ "version": "==17.1"
+ },
+ "pathlib2": {
+ "hashes": [
+ "sha256:8eb170f8d0d61825e09a95b38be068299ddeda82f35e96c3301a8a5e7604cb83",
+ "sha256:d1aa2a11ba7b8f7b21ab852b1fb5afb277e1bb99d5dfc663380b5015c0d80c5a"
+ ],
+ "index": "pypi",
+ "markers": "python_version < '3.5'",
+ "version": "==2.3.2"
+ },
+ "pbr": {
+ "hashes": [
+ "sha256:1b8be50d938c9bb75d0eaf7eda111eec1bf6dc88a62a6412e33bf077457e0f45",
+ "sha256:b486975c0cafb6beeb50ca0e17ba047647f229087bd74e37f4a7e2cac17d2caa"
+ ],
+ "version": "==4.2.0"
+ },
"pluggy": {
"hashes": [
"sha256:6e3836e39f4d36ae72840833db137f7b7d35105079aee6ec4a62d9f80d594dd1",
"sha256:95eb8364a4708392bae89035f45341871286a333f749c3141c20573d2b3876e1"
],
- "markers": "python_version != '3.0.*' and python_version != '3.2.*' and python_version != '3.1.*' and python_version != '3.3.*' and python_version >= '2.7'",
+ "markers": "python_version != '3.1.*' and python_version >= '2.7' and python_version != '3.0.*' and python_version != '3.2.*' and python_version != '3.3.*'",
"version": "==0.7.1"
},
"pudb": {
@@ -213,7 +308,7 @@
"sha256:06a30435d058473046be836d3fc4f27167fd84c45b99704f2fb5509ef61f9af1",
"sha256:50402e9d1c9005d759426988a492e0edaadb7f4e68bcddfea586bc7432d009c6"
],
- "markers": "python_version != '3.0.*' and python_version != '3.2.*' and python_version != '3.3.*' and python_version != '3.1.*' and python_version >= '2.7'",
+ "markers": "python_version != '3.1.*' and python_version >= '2.7' and python_version != '3.0.*' and python_version != '3.2.*' and python_version != '3.3.*'",
"version": "==1.6.0"
},
"pygments": {
@@ -231,13 +326,20 @@
"index": "pypi",
"version": "==2.1.1"
},
+ "pyparsing": {
+ "hashes": [
+ "sha256:0832bcf47acd283788593e7a0f542407bd9550a55a8a8435214a1960e04bcb04",
+ "sha256:fee43f17a9c4087e7ed1605bd6df994c6173c1e977d7ade7b651292fab2bd010"
+ ],
+ "version": "==2.2.0"
+ },
"pytest": {
"hashes": [
- "sha256:2e7c330338b2732ddb992217962e3454aa7290434e75329b1a6739cea41bea6b",
- "sha256:4abcd98faeea3eb95bd05aa6a7b121d5f89d72e4d36ddb0dcbbfd1ec9f3651d1"
+ "sha256:2d7c49e931316cc7d1638a3e5f54f5d7b4e5225972b3c9838f3584788d27f349",
+ "sha256:ad0c7db7b5d4081631e0155f5c61b80ad76ce148551aaafe3a718d65a7508b18"
],
"index": "pypi",
- "version": "==3.7.3"
+ "version": "==3.7.4"
},
"pytest-cov": {
"hashes": [
@@ -263,6 +365,52 @@
"index": "pypi",
"version": "==4.2"
},
+ "pytoml": {
+ "hashes": [
+ "sha256:dae3c4e31d09eb06a6076d671f2281ee5d2c43cbeae16599c3af20881bb818ac"
+ ],
+ "version": "==0.1.18"
+ },
+ "pytz": {
+ "hashes": [
+ "sha256:a061aa0a9e06881eb8b3b2b43f05b9439d6583c206d0a6c340ff72a7b6669053",
+ "sha256:ffb9ef1de172603304d9d2819af6f5ece76f2e85ec10692a524dd876e72bf277"
+ ],
+ "version": "==2018.5"
+ },
+ "requests": {
+ "hashes": [
+ "sha256:63b52e3c866428a224f97cab011de738c36aec0185aa91cfacd418b5d58911d1",
+ "sha256:ec22d826a36ed72a7358ff3fe56cbd4ba69dd7a6718ffd450ff0e9df7a47ce6a"
+ ],
+ "index": "pypi",
+ "version": "==2.19.1"
+ },
+ "requests-download": {
+ "hashes": [
+ "sha256:92d895a6ca51ea51aa42bab864bddaee31b5601c7e7e1ade4c27b0eb6695d846",
+ "sha256:994d9d332befae6616f562769bab163f08d6404dc7e28fb7bfed4a0a43a754ad"
+ ],
+ "version": "==0.1.2"
+ },
+ "scandir": {
+ "hashes": [
+ "sha256:04b8adb105f2ed313a7c2ef0f1cf7aff4871aa7a1883fa4d8c44b5551ab052d6",
+ "sha256:1444134990356c81d12f30e4b311379acfbbcd03e0bab591de2696a3b126d58e",
+ "sha256:1b5c314e39f596875e5a95dd81af03730b338c277c54a454226978d5ba95dbb6",
+ "sha256:346619f72eb0ddc4cf355ceffd225fa52506c92a2ff05318cfabd02a144e7c4e",
+ "sha256:44975e209c4827fc18a3486f257154d34ec6eaec0f90fef0cca1caa482db7064",
+ "sha256:61859fd7e40b8c71e609c202db5b0c1dbec0d5c7f1449dec2245575bdc866792",
+ "sha256:a5e232a0bf188362fa00123cc0bb842d363a292de7126126df5527b6a369586a",
+ "sha256:c14701409f311e7a9b7ec8e337f0815baf7ac95776cc78b419a1e6d49889a383",
+ "sha256:c7708f29d843fc2764310732e41f0ce27feadde453261859ec0fca7865dfc41b",
+ "sha256:c9009c527929f6e25604aec39b0a43c3f831d2947d89d6caaab22f057b7055c8",
+ "sha256:f5c71e29b4e2af7ccdc03a020c626ede51da471173b4a6ad1e904f2b2e04b4bd"
+ ],
+ "index": "pypi",
+ "markers": "python_version < '3.5'",
+ "version": "==1.9.0"
+ },
"six": {
"hashes": [
"sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9",
@@ -270,6 +418,83 @@
],
"version": "==1.11.0"
},
+ "snowballstemmer": {
+ "hashes": [
+ "sha256:919f26a68b2c17a7634da993d91339e288964f93c274f1343e3bbbe2096e1128",
+ "sha256:9f3bcd3c401c3e862ec0ebe6d2c069ebc012ce142cce209c098ccb5b09136e89"
+ ],
+ "version": "==1.2.1"
+ },
+ "sphinx": {
+ "hashes": [
+ "sha256:a07050845cc9a2f4026a6035cc8ed795a5ce7be6528bbc82032385c10807dfe7",
+ "sha256:d719de667218d763e8fd144b7fcfeefd8d434a6201f76bf9f0f0c1fa6f47fcdb"
+ ],
+ "index": "pypi",
+ "version": "==1.7.8"
+ },
+ "sphinxcontrib-websupport": {
+ "hashes": [
+ "sha256:68ca7ff70785cbe1e7bccc71a48b5b6d965d79ca50629606c7861a21b206d9dd",
+ "sha256:9de47f375baf1ea07cdb3436ff39d7a9c76042c10a769c52353ec46e4e8fc3b9"
+ ],
+ "markers": "python_version != '3.1.*' and python_version >= '2.7' and python_version != '3.0.*' and python_version != '3.2.*' and python_version != '3.3.*'",
+ "version": "==1.1.0"
+ },
+ "tox": {
+ "hashes": [
+ "sha256:37cf240781b662fb790710c6998527e65ca6851eace84d1595ee71f7af4e85f7",
+ "sha256:eb61aa5bcce65325538686f09848f04ef679b5cd9b83cc491272099b28739600"
+ ],
+ "index": "pypi",
+ "version": "==3.2.1"
+ },
+ "typed-ast": {
+ "hashes": [
+ "sha256:0948004fa228ae071054f5208840a1e88747a357ec1101c17217bfe99b299d58",
+ "sha256:10703d3cec8dcd9eef5a630a04056bbc898abc19bac5691612acba7d1325b66d",
+ "sha256:1f6c4bd0bdc0f14246fd41262df7dfc018d65bb05f6e16390b7ea26ca454a291",
+ "sha256:25d8feefe27eb0303b73545416b13d108c6067b846b543738a25ff304824ed9a",
+ "sha256:29464a177d56e4e055b5f7b629935af7f49c196be47528cc94e0a7bf83fbc2b9",
+ "sha256:2e214b72168ea0275efd6c884b114ab42e316de3ffa125b267e732ed2abda892",
+ "sha256:3e0d5e48e3a23e9a4d1a9f698e32a542a4a288c871d33ed8df1b092a40f3a0f9",
+ "sha256:519425deca5c2b2bdac49f77b2c5625781abbaf9a809d727d3a5596b30bb4ded",
+ "sha256:57fe287f0cdd9ceaf69e7b71a2e94a24b5d268b35df251a88fef5cc241bf73aa",
+ "sha256:668d0cec391d9aed1c6a388b0d5b97cd22e6073eaa5fbaa6d2946603b4871efe",
+ "sha256:68ba70684990f59497680ff90d18e756a47bf4863c604098f10de9716b2c0bdd",
+ "sha256:6de012d2b166fe7a4cdf505eee3aaa12192f7ba365beeefaca4ec10e31241a85",
+ "sha256:79b91ebe5a28d349b6d0d323023350133e927b4de5b651a8aa2db69c761420c6",
+ "sha256:8550177fa5d4c1f09b5e5f524411c44633c80ec69b24e0e98906dd761941ca46",
+ "sha256:898f818399cafcdb93cbbe15fc83a33d05f18e29fb498ddc09b0214cdfc7cd51",
+ "sha256:94b091dc0f19291adcb279a108f5d38de2430411068b219f41b343c03b28fb1f",
+ "sha256:a26863198902cda15ab4503991e8cf1ca874219e0118cbf07c126bce7c4db129",
+ "sha256:a8034021801bc0440f2e027c354b4eafd95891b573e12ff0418dec385c76785c",
+ "sha256:bc978ac17468fe868ee589c795d06777f75496b1ed576d308002c8a5756fb9ea",
+ "sha256:c05b41bc1deade9f90ddc5d988fe506208019ebba9f2578c622516fd201f5863",
+ "sha256:c9b060bd1e5a26ab6e8267fd46fc9e02b54eb15fffb16d112d4c7b1c12987559",
+ "sha256:edb04bdd45bfd76c8292c4d9654568efaedf76fe78eb246dde69bdb13b2dad87",
+ "sha256:f19f2a4f547505fe9072e15f6f4ae714af51b5a681a97f187971f50c283193b6"
+ ],
+ "markers": "python_version < '3.7' and implementation_name == 'cpython'",
+ "version": "==1.1.0"
+ },
+ "typing": {
+ "hashes": [
+ "sha256:4027c5f6127a6267a435201981ba156de91ad0d1d98e9ddc2aa173453453492d",
+ "sha256:57dcf675a99b74d64dacf6fba08fb17cf7e3d5fdff53d4a30ea2a5e7e52543d4",
+ "sha256:a4c8473ce11a65999c8f59cb093e70686b6c84c98df58c1dae9b3b196089858a"
+ ],
+ "markers": "python_version < '3.5'",
+ "version": "==3.6.6"
+ },
+ "urllib3": {
+ "hashes": [
+ "sha256:a68ac5e15e76e7e5dd2b8f94007233e01effe3e50e8daddf69acfd81cb686baf",
+ "sha256:b5725a0bd4ba422ab0e66e89e030c806576753ea3ee08554382c14e685d117b5"
+ ],
+ "markers": "python_version != '3.1.*' and python_version != '3.3.*' and python_version < '4' and python_version != '3.0.*' and python_version != '3.2.*' and python_version >= '2.6'",
+ "version": "==1.23"
+ },
"urwid": {
"hashes": [
"sha256:644d3e3900867161a2fc9287a9762753d66bd194754679adb26aede559bcccbc"
@@ -277,11 +502,27 @@
"index": "pypi",
"version": "==2.0.1"
},
+ "virtualenv": {
+ "hashes": [
+ "sha256:2ce32cd126117ce2c539f0134eb89de91a8413a29baac49cbab3eb50e2026669",
+ "sha256:ca07b4c0b54e14a91af9f34d0919790b016923d157afda5efdde55c96718f752"
+ ],
+ "markers": "python_version >= '2.7' and python_version != '3.0.*' and python_version != '3.2.*' and python_version != '3.1.*'",
+ "version": "==16.0.0"
+ },
"wrapt": {
"hashes": [
"sha256:d4d560d479f2c21e1b5443bbd15fe7ec4b37fe7e53d335d3b9b0a7b1226fe3c6"
],
"version": "==1.10.11"
+ },
+ "zipfile36": {
+ "hashes": [
+ "sha256:a78a8dddf4fa114f7fe73df76ffcce7538e23433b7a6a96c1c904023f122aead",
+ "sha256:f7e48adf627f75cd74cdb50e7d850623b465f4cf5de913809196e8f3aa57dc4b"
+ ],
+ "markers": "python_version in '3.3 3.4 3.5'",
+ "version": "==0.1.3"
}
}
}
diff --git a/README.md b/README.md
deleted file mode 100644
index 0852303..0000000
--- a/README.md
+++ /dev/null
@@ -1,307 +0,0 @@
-nncli
-=====
-
-![GitHub](https://img.shields.io/github/license/djmoch/nncli.svg)
-[![PyPI](https://img.shields.io/pypi/v/nncli.svg)](https://pypi.org/project/nncli/)
-
-NextCloud Notes Command Line Interface
-
-nncli is a Python application that gives you access to your NextCloud
-Notes account via the command line. It's a "hard" fork of
-[sncli](https://github.com/insanum/sncli). You can access your notes via
-a customizable console GUI that implements vi-like keybinds or via a
-simple command line interface that you can script.
-
-Notes can be viewed/created/edited in *both an* **online** *and*
-**offline** *mode*. All changes are saved to a local cache on disk and
-automatically sync'ed when nncli is brought online.
-
-**Pull requests are welcome!**
-
-Check your OS distribution for installation packages.
-
-### Requirements
-
-* [Python 3](http://python.org)
-* [Urwid](http://urwid.org) Python 3 module
-* [Requests](https://requests.readthedocs.org/en/master/) Python 3
- module
-* A love for the command line!
-
-### Installation
-
-* Via pip (latest release):
- - `pip3 install nncli`
-* Manually:
- - Clone this repository to your hard disk: `git clone
- https://github.com/djmoch/nncli.git`
- - Install _nncli_: `python3 setup.py install`
-* Development:
- - Clone the repo
- - Install Pipenv: `pip install pipenv`
- - Stand up development environment: `pipenv install --dev`
-
-### Features
-
-* Console GUI
- - full two-way sync with NextCloud Notes performed dynamically in the
- background
- - all actions logged and easily reviewed
- - list note titles (configurable format w/ title, date, flags, category,
- keys, etc)
- - sort notes by date, alpha by title, category, favorite on top
- - search for notes using a Google style search pattern or Regular
- Expression
- - view note contents and meta data
- - pipe note contents to external command
- - create and edit notes (using your editor)
- - edit note category
- - delete notes
- - favorite/unfavorite notes
- - vi-like keybinds (fully configurable)
- - Colors! (fully configurable)
-* Command Line (scripting)
- - force a full two-way sync with NextCloud Notes
- - all actions logged and easily reviewed
- - list note titles and keys
- - search for notes using a Google style search pattern or Regular
- Expression
- - dump note contents
- - create a new note (via stdin or editor)
- - import a note with raw json data (stdin or editor)
- - edit a note (via editor)
- - delete a note
- - favorite/unfavorite a note
- - view and edit note category
-
-### HowTo
-
-```
-Usage:
- nncli [OPTIONS] [COMMAND] [COMMAND_ARGS]
-
- OPTIONS:
- -h, --help - usage help
- -v, --verbose - verbose output
- -n, --nosync - don't perform a server sync
- -r, --regex - search string is a regular expression
- -k <key>, --key=<key> - note key
- -t <title>, --title=<title> - title of note for create (cli mode)
- -c <file>, --config=<file> - config file to read from
- --version - version information
-
- COMMANDS:
- <none> - console gui mode when no command specified
- sync - perform a full sync with the server
- list [search_string] - list notes (refined with search string)
- export [search_string] - export notes in JSON (refined with search string)
- dump [search_string] - dump notes (refined with search string)
- create [-] - create a note ('-' content from stdin)
- import [-] - import a note in JSON format ('-' JSON from stdin)
- export - export a note in JSON format (specified by <key>)
- dump - dump a note (specified by <key>)
- edit - edit a note (specified by <key>)
- delete - delete a note (specified by <key>)
- < favorite | unfavorite > - favorite/unfavorite a note (specified by <key>)
- cat get - retrieve the category from a note (specified by <key>)
- cat set <category> - set the category for a note (specified by <key>)
- cat rm - remove category from a note (specified by <key>)
-```
-
-#### Configuration
-
-The current NextCloud Notes API does not support oauth authentication so
-your NextCloud Notes account password must be stored someplace
-accessible to nncli. Use of the `cfg_nn_password_eval` option is
-recommended (see below).
-
-nncli pulls in configuration from the `config` file located in the
-standard location for your platform. At the very least, the following
-example `config` will get you going (using your account information):
-
-```
-[nncli]
-cfg_nn_username = lebowski@thedude.com
-cfg_nn_password = nihilist
-cfg_nn_host = nextcloud.thedude.com
-```
-
-Start nncli with no arguments which starts the console GUI mode. nncli
-will begin to sync your existing notes and you'll see log messages at
-the bottom of the console. You can view these log messages at any time
-by pressing the `l` key.
-
-View the help by pressing `h`. Here you'll see all the keybinds and
-configuration items. The middle column shows the config name that can be
-used in your `config` to override the default setting.
-
-See example configuration file below for more notes.
-
-```
-[nncli]
-cfg_nn_username = lebowski@thedude.com
-cfg_nn_password = nihilist
-cfg_nn_host = nextcloud.thedude.com
-
-# as an alternate to cfg_nn_password you could use the following config item
-# any shell command can be used; its stdout is used for the password
-# trailing newlines are stripped for ease of use
-# note: if both password config are given, cfg_nn_password will be used
-cfg_nn_password_eval = gpg --quiet --for-your-eyes-only --no-tty --decrypt ~/.nncli-pass.gpg
-
-# see http://urwid.org/manual/userinput.html for examples of more key
-# combinations
-kb_edit_note = space
-kb_page_down = ctrl f
-
-# note that values must not be quoted
-clr_note_focus_bg = light blue
-
-# if this editor config value is not provided, the $EDITOR env var will be
-# used instead
-# warning: if neither $EDITOR or cfg_editor is set, it will be impossible to
-# edit notes
-cfg_editor = nvim
-
-# alternatively, {fname} and/or {line} are substituted with the filename and
-# current line number in nncli's pager.
-# If {fname} isn't supplied, the filename is simply appended.
-# examples:
-cfg_editor = nvim {fname} +{line}
-cfg_editor = nano +{line}
-
-# this is also supported for the pager:
-cfg_pager = less -c +{line} -N {fname}
-```
-
-#### Note Title Format
-
-The format of each line in the note list is driven by the
-`cfg_format_note_title` config item. Various formatting tags are
-supported for dynamically building the title string. Each of these
-formatting tags supports a width specifier (decimal) and a left
-justification (-) like that supported by printf:
-
-```
-%F - flags (fixed 5 char width)
- X - needs sync
- * - favorited
-%T - category
-%D - date
-%N - title
-```
-
-The default note title format pushes the note category to the far right of
-the terminal and left justifies the note title after the date and flags:
-
-``` cfg_format_note_title = '[%D] %F %-N %T' ```
-
-Note that the `%D` date format is further defined by the strftime format
-specified in `cfg_format_strftime`.
-
-#### Colors
-
-nncli utilizes the Python [Uwrid](http://urwid.org) module to implement
-the console user interface.
-
-At this time, nncli does not yet support 256-color terminals and is
-limited to just 16-colors. Color names that can be specified in the
-`config` file are listed
-[here](http://urwid.org/manual/displayattributes.html#standard-foreground-colors).
-
-### Searching
-
-nncli supports two styles of search strings. First is a Google style
-search string and second is a Regular Expression.
-
-A Google style search string is a group of tokens (separated by spaces)
-with an implied *AND* between each token. This style search is case
-insensitive. For example:
-
-`/category:category1 category:category2 word1 "word2 word3" category:category3`
-
-Regular expression searching also supports the use of flags (currently
-only case-insensitive) by adding a final forward slash followed by the
-flags. The following example will do a case-insensitive search for
-`something`:
-
-`(regex) /something/i`
-
-### Creating from command line
-
-```
-# create a new note and open in editor
-nncli create
-
-# create a new note with contents of stdin
-echo 'hi' | nncli create -
-```
-
-### Importing
-
-nncli can import notes from raw json data (via stdin or editor). For
-example:
-
-`echo '{"category":"testing","content":"New note!"}' | nncli import - `
-
-Allowed fields are `content`, `category`, `favorite`, and `modified`
-
-### Exporting
-
-nncli can export notes as json data to stdout. Example:
-
-```
-# export a single note by id
-nncli -k somekeyid export
-
-# export all notes
-nncli export
-
-# export notes matching search string
-nncli [-r] export some search keywords or regex
-```
-
-Note that nncli still stores all the notes data in the directory
-specified by `cfg_db_path`, so for easy backups, it may be
-easier/quicker to simply backup this entire directory.
-
-### Category
-
-Note category can be modified directly from the command line. Example:
-
-```
-# Retrieve note category (e.g. "category1")
-nncli -k somekeyid cat get
-# Returns "category1"
-
-# Add a category to a note, overwriting any existing one
-nncli -k somekeyid cat set "category3"
-# Now tagged as "category3"
-
-# Remove a category from a note
-nncli -k somekeyid cat rm
-# Note now has no category
-```
-### Tricks
-
-Advanced text editors usually tailor their behavior based on the file
-type being edited. For such editors, notes opened through nncli should
-be treated as Markdown by default. However, you can change this
-on a per-note basis through the use of modelines. In Vim, for instance,
-a modeline is a comment line conforming to the pattern below.
-
-``` ; vim:ft=votl ```
-
-Now when I edit this note Vim will automatically load the votl plugin.
-Lots of possibilities here...
-
-### Thanks
-
-nncli is a fork of [sncli](https://github.com/insanum/sncli) by
-[insanum](https://github.com/insanum). This application further pulls in
-and uses modified versions of the
-[simplenote.py](https://github.com/mrtazz/simplenote.py) module by
-[mrtazz](https://github.com/mrtazz) and the
-[notes_db.py](https://github.com/cpbotha/nvpy/blob/master/nvpy/notes_db.py)
-module from [nvpy](https://github.com/cpbotha/nvpy) by
-[cpbotha](https://github.com/cpbotha).
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..3638ea0
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,132 @@
+.. image:: https://img.shields.io/pypi/l/nncli.svg
+ :alt: PyPI - License
+.. image:: https://img.shields.io/travis/com/djmoch/nncli.svg
+ :alt: Travis (.com)
+ :target: https://travis-ci.com/djmoch/nncli
+.. image:: https://img.shields.io/pypi/v/nncli.svg
+ :alt: PyPI
+ :target: https://pypi.org/project/nncli
+.. image:: https://img.shields.io/coveralls/github/djmoch/nncli.svg
+ :alt: Coveralls github
+ :target: https://coveralls.io/github/djmoch/nncli
+.. image:: https://img.shields.io/readthedocs/nncli.svg
+ :alt: Read the Docs
+ :target: https://nncli.readthedocs.io
+
+nncli is a Python application that gives you access to your NextCloud
+Notes account via the command line. It's a "hard" fork of
+sncli_. You can access your notes via
+a customizable console GUI that implements vi-like keybinds or via a
+simple command line interface that you can script.
+
+Notes can be viewed/created/edited in *both an* **online** *and*
+**offline** *mode*. All changes are saved to a local cache on disk and
+automatically sync'ed when nncli is brought online.
+
+More detailed documentation can be found in the docs.
+
+Requirements
+~~~~~~~~~~~~
+
+- `Python 3`_
+
+- Urwid_ Python 3 module
+
+- Requests_ Python 3 module
+
+- A love for the command line!
+
+Installation
+~~~~~~~~~~~~
+
+- Via pip (latest release):
+
+ - ``pip3 install nncli``
+
+- Manually:
+
+ - Clone this repository to your hard disk: ``git clone
+ https://github.com/djmoch/nncli.git``
+
+ - Install nncli: ``python3 setup.py install``
+
+- Development:
+
+ - Clone the repo
+
+ - Install Pipenv: ``pip install pipenv``
+
+ - Stand up development environment: ``pipenv install --dev``
+
+Features
+~~~~~~~~
+
+- Console GUI
+
+ - full two-way sync with NextCloud Notes performed dynamically in the
+ background
+
+ - all actions logged and easily reviewed
+
+ - list note titles (configurable format w/ title, date, flags, category,
+ keys, etc)
+
+ - sort notes by date, alpha by title, category, favorite on top
+
+ - search for notes using a Google style search pattern or Regular
+ Expression
+
+ - view note contents and meta data
+
+ - pipe note contents to external command
+
+ - create and edit notes (using your editor)
+
+ - edit note category
+
+ - delete notes
+
+ - favorite/unfavorite notes
+
+ - vi-like keybinds (fully configurable)
+
+ - Colors! (fully configurable)
+
+- Command Line (scripting)
+
+ - force a full two-way sync with NextCloud Notes
+
+ - all actions logged and easily reviewed
+
+ - list note titles and keys
+
+ - search for notes using a Google style search pattern or Regular
+ Expression
+
+ - dump note contents
+
+ - create a new note (via stdin or editor)
+
+ - import a note with raw json data (stdin or editor)
+
+ - edit a note (via editor)
+
+ - delete a note
+
+ - favorite/unfavorite a note
+
+ - view and edit note category
+
+Acknowledgements
+~~~~~~~~~~~~~~~~
+
+nncli is a fork of sncli_ by Eric Davis. This application further pulls in
+and uses modified versions of the simplenote.py_ module by Daniel Schauenberg and
+the notes_db.py module from nvpy_ by Charl P. Botha.
+
+.. _sncli: https://github.com/insanum/sncli
+.. _Python 3: http://python.org
+.. _Urwid: http://urwid.org
+.. _Requests: https://requests.readthedocs.org/en/master
+.. _simplenote.py: https://github.com/mrtazz/simplenote.py
+.. _nvpy: https://github.com/cpbotha/nvpy
diff --git a/docs/Makefile b/docs/Makefile
new file mode 100644
index 0000000..855249f
--- /dev/null
+++ b/docs/Makefile
@@ -0,0 +1,20 @@
+# Minimal makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = pipenv run sphinx-build
+SPHINXPROJ = nncli
+SOURCEDIR = source
+BUILDDIR = build
+
+# Put it first so that "make" without argument is like "make help".
+help:
+ @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+
+.PHONY: help Makefile
+
+# Catch-all target: route all unknown targets to Sphinx using the new
+# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
+%: Makefile
+ @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
diff --git a/docs/source/conf.py b/docs/source/conf.py
new file mode 100644
index 0000000..baedf52
--- /dev/null
+++ b/docs/source/conf.py
@@ -0,0 +1,176 @@
+# -*- coding: utf-8 -*-
+#
+# Configuration file for the Sphinx documentation builder.
+#
+# This file does only contain a selection of the most common options. For a
+# full list see the documentation:
+# http://www.sphinx-doc.org/en/master/config
+
+# -- Path setup --------------------------------------------------------------
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#
+import os
+import sys
+sys.path.insert(0, os.path.abspath(os.path.sep.join(['..', '..'])))
+import nncli
+
+# -- Project information -----------------------------------------------------
+
+project = 'nncli'
+copyright = '2018, Daniel Moch'
+author = 'Daniel Moch'
+
+# The short X.Y version
+version = nncli.__version__
+# The full version, including alpha/beta/rc tags
+release = nncli.__version__
+
+
+# -- General configuration ---------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#
+# needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = [
+ 'sphinx.ext.autodoc',
+ 'sphinx.ext.todo',
+ 'sphinx.ext.intersphinx',
+]
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['.templates']
+
+# The suffix(es) of source filenames.
+# You can specify multiple suffix as a list of string:
+#
+# source_suffix = ['.rst', '.md']
+source_suffix = '.rst'
+
+# The master toctree document.
+master_doc = 'index'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#
+# This is also used if you do content translation via gettext catalogs.
+# Usually you set "language" from the command line for these cases.
+language = None
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This pattern also affects html_static_path and html_extra_path .
+exclude_patterns = []
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+
+# -- Options for HTML output -------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+#
+html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#
+# html_theme_options = {}
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['.static']
+
+# Custom sidebar templates, must be a dictionary that maps document names
+# to template names.
+#
+# The default sidebars (for documents that don't match any pattern) are
+# defined by theme itself. Builtin themes are using these templates by
+# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
+# 'searchbox.html']``.
+#
+# html_sidebars = {}
+
+
+# -- Options for HTMLHelp output ---------------------------------------------
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'nnclidoc'
+
+
+# -- Options for LaTeX output ------------------------------------------------
+
+latex_elements = {
+ # The paper size ('letterpaper' or 'a4paper').
+ #
+ # 'papersize': 'letterpaper',
+
+ # The font size ('10pt', '11pt' or '12pt').
+ #
+ # 'pointsize': '10pt',
+
+ # Additional stuff for the LaTeX preamble.
+ #
+ # 'preamble': '',
+
+ # Latex figure (float) alignment
+ #
+ # 'figure_align': 'htbp',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+# author, documentclass [howto, manual, or own class]).
+latex_documents = [
+ (master_doc, 'nncli.tex', 'nncli Documentation',
+ 'Daniel Moch', 'manual'),
+]
+
+
+# -- Options for manual page output ------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ (master_doc, 'nncli', 'nncli Documentation',
+ [author], 1)
+]
+
+
+# -- Options for Texinfo output ----------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+texinfo_documents = [
+ (master_doc, 'nncli', 'nncli Documentation',
+ author, 'nncli', 'One line description of project.',
+ 'Miscellaneous'),
+]
+
+
+# -- Extension configuration -------------------------------------------------
+
+# -- Options for intersphinx extension ---------------------------------------
+intersphinx_mapping = {'python': ('https://docs.python.org/3', None),
+ 'urwid': ('http://urwid.org', None)}
+
+# -- Options for todo extension ----------------------------------------------
+
+# If true, `todo` and `todoList` produce output, else they produce nothing.
+todo_include_todos = True
+
+# -- Extension interface -----------------------------------------------------
+def setup(app):
+ app.add_object_type('confval', 'confval',
+ objname='configuration value',
+ indextemplate='pair: %s; configuration value')
diff --git a/docs/source/configuration.rst b/docs/source/configuration.rst
new file mode 100644
index 0000000..fd6fa80
--- /dev/null
+++ b/docs/source/configuration.rst
@@ -0,0 +1,725 @@
+.. _configuration:
+
+Configuration
+=============
+
+The current NextCloud Notes API does not support oauth authentication so
+your NextCloud Notes account password must be stored someplace
+accessible to nncli. Use of the ``cfg_nn_password_eval`` option is
+recommended (see :ref:`config-file`).
+
+.. index:: single: configuration file
+
+.. _config-file:
+
+Configuration File
+------------------
+
+nncli pulls in configuration from the ``config`` file located in the
+standard location for your platform.
+
+- Windows: ``%USERPROFILE%\AppData\Local\djmoch\nncli``
+
+- macOS: ``~/Library/Preferences/nncli``
+
+- \*nix: ``$XDG_CONFIG_HOME/nncli/config`` or
+ ``$HOME/.config/nncli/config``
+
+The following directives are accepted within the ``config`` file:
+
+.. index:: pair: configuration file; general options
+
+General Options
+~~~~~~~~~~~~~~~
+
+.. confval:: cfg_nn_host
+
+ Sets the URL of the NextCloud instance to connect to.
+
+ Required.
+
+.. confval:: cfg_nn_username
+
+ The user name to log in as.
+
+ Required.
+
+.. confval:: cfg_nn_password
+
+ The password to use for log in.
+
+ Optional. Overrides :confval:`cfg_nn_password_eval` if both are
+ specified.
+
+.. confval:: cfg_nn_password_eval
+
+ A command to run to retrieve the password. The command should return
+ the password on ``stdout``.
+
+ Optional. Required if :confval:`cfg_nn_password` is not specified.
+
+.. confval:: cfg_db_path
+
+ Specifies the path of the local notes cache.
+
+ Optional. Default value:
+
+ - Windows: ``%USERPROFILE%\AppData\Local\djmoch\nncli\Cache``
+
+ - macOS: ``~/Library/Caches/nncli``
+
+ - \*nix: ``~/.cache/nncli``
+
+.. confval:: cfg_search_categories
+
+ Set to ``yes`` to include categories in searches. Otherwise set to
+ ``no``.
+
+ Optional. Default value: ``yes``
+
+.. confval:: cfg_sort_mode
+
+ Sets how notes are sorted in the console GUI. Set to ``date``
+ to have them sorted by date (newest on top). Set to ``alpha`` to have
+ them sorted alphabetically.
+
+ Optional. Default value: ``date``
+
+.. confval:: cfg_favorite_ontop
+
+ Determines whether notes marked as favorite are sorted on top.
+
+ Optional. Default value: ``yes``
+
+.. confval:: cfg_tabstop
+
+ Sets the width of a tabstop character.
+
+ Optional. Default value: ``4``
+
+.. confval:: cfg_format_strftime
+
+ Sets the format of the note timestamp (``%D``) in the note title. The
+ format values are the specified in :py:func:`time.strftime`.
+
+ Optional. Default value: ``%Y/%m/%d``
+
+.. confval:: cfg_format_note_title
+
+ Sets the format of each line in the console GUI note list. Various
+ formatting tags are supported for dynamically building the title
+ string. Each of these formatting tags supports a width specifier
+ (decimal) and a left justification (``-``) like that supported by
+ printf:
+
+ .. code-block:: none
+
+ %F - flags (fixed 2 char width)
+ X - needs sync
+ * - favorited
+ %T - category
+ %D - date
+ %N - title
+
+ The default note title format pushes the note category to the far
+ right of the terminal and left justifies the note title after the
+ date and flags.
+
+ Optional. Default value: ``[%D] %F %-N %T``
+
+ Note that the ``%D`` date format is further defined by the strftime
+ format specified in :confval:`cfg_format_strftime`.
+
+.. confval:: cfg_status_bar
+
+ Sets whether or not the status bar is visible at the top of the
+ console GUI.
+
+ Optional. Default value: ``yes``
+
+.. confval:: cfg_editor
+
+ Sets the command to run when opening a note for editing. The special
+ values ``{fname}`` and ``{line}`` can be used to specify respectively
+ the file name and line number to pass to the command.
+
+ Optional. Default value: ``$EDITOR`` if defined in the user's
+ environment, else ``vim {fname} +{line}``.
+
+.. confval:: cfg_pager
+
+ Sets the command to run when opening a note for viewing in an
+ external pager.
+
+ Optional. Default value: ``$PAGER`` if defined in the user's
+ environment, else ``less -c``.
+
+.. confval:: cfg_diff
+
+ .. todo:: Remove ``cfg_diff``
+
+.. confval:: cfg_max_logs
+
+ Sets the number of log events to display together in the consule GUI
+ footer.
+
+ Optional. Default value: ``5``
+
+.. confval:: cfg_log_timeout
+
+ Sets the rate to poll for log events. Unit is seconds.
+
+ Optional. Default value: ``5``
+
+.. confval:: cfg_log_reversed
+
+ Sets whether or not the log is displayed in reverse-chronological
+ order.
+
+ Optional. Default value: ``yes``
+
+.. confval:: cfg_tempdir
+
+ Sets a directory path to store temporary files in. ``nncli`` uses
+ :func:`tempfile.mkstemp` under the hood, and the most nuanced
+ description of how this value is used can be found in the discussion
+ of the ``dir`` keyword argument there. Basically you should not
+ specify this if you want to use the platform-standard temporary
+ folder.
+
+ Optional. Default value: *[blank]*
+
+.. index:: pair: configuration file; keybindings
+
+Keybindings
+~~~~~~~~~~~
+
+Keybindings specify the behavior of the console GUI, and are never
+required in the ``config`` file. However, they all have default values,
+as outlined below. More information on specifying keybindings can be
+found in the :ref:`Urwid documentation <urwid:keyboard-input>`.
+
+.. confval:: kb_help
+
+ Press to enter the help screen.
+
+ Default value: ``h``
+
+.. confval:: kb_quit
+
+ Press to exit the console GUI.
+
+ Default value: ``q``
+
+.. confval:: kb_sync
+
+ Press to force a full, bi-directional sync with the server.
+
+ Default value: ``S``
+
+.. confval:: kb_down
+
+ Press to move down one row.
+
+ Default value: ``j``
+
+.. confval:: kb_up
+
+ Press to move one row up.
+
+ Default value: ``k``
+
+.. confval:: kb_page_down
+
+ Press to move one page down.
+
+ Default value: ``space``
+
+.. confval:: kb_page_up
+
+ Press to move one page up.
+
+ Default value: ``b``
+
+.. confval:: kb_half_page_down
+
+ Press to move one half-page down.
+
+ Default value: ``ctrl d``
+
+.. confval:: kb_half_page_up
+
+ Press to move one half-page up.
+
+ Default value: ``ctrl u``
+
+.. confval:: kb_bottom
+
+ Press to move to the last line.
+
+ Default value: ``G``
+
+.. confval:: kb_top
+
+ Press to move to the first line.
+
+ Default value: ``g``
+
+.. confval:: kb_status
+
+ Press to toggle the visibility of the status bar.
+
+ Default value: ``s``
+
+.. confval:: kb_create_note
+
+ Press to create a new note and open in the configured editor (see
+ :confval:`cfg_editor`).
+
+ Default value: ``C``
+
+.. confval:: kb_edit_note
+
+ Press to edit the highlighted note in the configured editor (see
+ :confval:`cfg_editor`).
+
+ Default value: ``e``
+
+.. confval:: kb_view_note
+
+ Press to view the highlighted note in read-only mode.
+
+ Default value: ``enter``
+
+.. confval:: kb_view_note_ext
+
+ Press to view the highlighted note in the configured pager (see
+ :confval:`cfg_pager`).
+
+ Default value: ``meta enter``
+
+.. confval:: kb_view_note_json
+
+ Press to view the raw JSON contents of the highlighted note in
+ read-only mode.
+
+ Default value: ``O``
+
+.. confval:: kb_pipe_note
+
+ Press to send the contents of the highlighted note to ``stdin`` of
+ another program. A small command window opens at the bottom of the
+ screen to enter the desired program.
+
+ Default value: ``|``
+
+.. confval:: kb_view_next_note
+
+ Press to view the contents of the next note in read-only mode.
+
+ Default value: ``J``
+
+.. confval:: kb_view_prev_note
+
+ Press to view the contents of the previous note in read-only mode.
+
+ Default value: ``K``
+
+.. confval:: kb_view_log
+
+ Press to view the log.
+
+ Default value: ``l``
+
+.. confval:: kb_tabstop2
+
+ Press to set the tabstop for the internal pager to a width of two
+ characters.
+
+ Default value: ``2``
+
+.. confval:: kb_tabstop4
+
+ Press to set the tabstop for the internal pager to a width of four
+ characters.
+
+ Default value: ``4``
+
+.. confval:: kb_tabstop8
+
+ Press to set the tabstop for the internal pager to a width of eight
+ characters.
+
+ Default value: ``8``
+
+.. confval:: kb_search_gstyle
+
+ Press to initiate a search of your notes against a Google-style
+ search term. A command window will open at the bottom of the screen
+ to enter your search term.
+
+ Default value: ``/``
+
+.. confval:: kb_search_regex
+
+ Press to initiate a search of your notes against a regular
+ expression. A command window will open at the bottom of the screen to
+ enter your search term.
+
+ Default value: ``meta /``
+
+.. confval:: kb_search_prev_gstyle
+
+ Press to initiate a reverse search of your notes against a
+ Google-style search term. A command window will open at the bottom of
+ the screen to enter your search term.
+
+ Default value: ``?``
+
+.. confval:: kb_search_prev_regex
+
+ Press to initiate a reverse search of your notes against a regular
+ expression. A command window will open at the bottom of the screen
+ to enter your search term.
+
+ Default value: ``meta ?``
+
+.. confval:: kb_search_next
+
+ Press after a search has been initiated to move to the next match.
+
+ Default value: ``n``
+
+.. confval:: kb_search_prev
+
+ Press after a search has been initiated to move to the previous
+ match.
+
+ Default value: ``N``
+
+.. confval:: kb_clear_search
+
+ Press to clear the current search.
+
+ Default value: ``A``
+
+.. confval:: kb_sort_date
+
+ Press to display notes sorted by date.
+
+ Default value: ``d``
+
+.. confval:: kb_sort_alpha
+
+ Press to display notes sorted alphabetically.
+
+ Default value: ``a``
+
+.. confval:: kb_sort_categories
+
+ Press to display notes sorted by category.
+
+ Default value: ``ctrl t``
+
+.. confval:: kb_note_delete
+
+ Press to delete a note. The note will be deleted locally and
+ reflected on the server after the next full sync (see
+ :confval:`kb_sync`).
+
+ Default value: ``D``
+
+.. confval:: kb_note_favorite
+
+ Press to toggle the ``favorite`` flag for a note.
+
+ Default value: ``p``
+
+.. confval:: kb_note_category
+
+ Press to set/edit the note category. A command window will appear at
+ the bottom of the screen containing the current category (if it has
+ one). Set to an empty string to clear the category.
+
+ Default value: ``t``
+
+.. confval:: kb_copy_note_text
+
+ Press to copy the note text to the system clipboard.
+
+ Default value: ``y``
+
+.. index:: pair: configuration file; colors
+
+Colors
+~~~~~~
+
+nncli utilizes the Python Urwid_ module to implement the console user
+interface.
+
+At this time, nncli does not yet support 256-color terminals and is
+limited to just 16-colors. Color names that can be specified in the
+``config`` file are listed :ref:`here <urwid:16-standard-foreground>`.
+
+The following pairs of configuration values represent the foreground and
+background colors for different elements of the console GUI. In each
+case the configuration value corresponding to the foreground color ends
+in ``_fg``, and the configuration value corresponding to the
+background color ends in ``_bg``. The default color values are listed in
+foreground/background format.
+
+.. _Urwid: http://urwid.org
+
+.. confval:: clr_default_fg
+
+.. confval:: clr_default_bg
+
+ The default foreground/background colors.
+
+ Default values: ``default/default``
+
+.. confval:: clr_status_bar_fg
+
+.. confval:: clr_status_bar_bg
+
+ The foreground/background colors for the status bar.
+
+ Default values: ``dark gray/light gray``
+
+.. confval:: clr_log_fg
+
+.. confval:: clr_log_bg
+
+ The foreground/background colors for the log.
+
+ Default values: ``dark gray/light gray``
+
+.. confval:: clr_user_input_bar_fg
+
+.. confval:: clr_user_input_bar_bg
+
+ The foreground/background colors for the input bar.
+
+ Default values: ``white/light red``
+
+.. confval:: clr_note_focus_fg
+
+.. confval:: clr_note_focus_bg
+
+ The foreground/background colors for the selected note.
+
+ Default values: ``white/light red``
+
+.. confval:: clr_note_title_day_fg
+
+.. confval:: clr_note_title_day_bg
+
+ The foreground/background colors for notes edited within the past 24
+ hours.
+
+ Default values: ``light red/default``
+
+.. confval:: clr_note_title_week_fg
+
+.. confval:: clr_note_title_week_bg
+
+ The foreground/background colors for notes edited within the past
+ week,
+
+ Default values: ``light green/default``
+
+.. confval:: clr_note_title_month_fg
+
+.. confval:: clr_note_title_month_bg
+
+ The foreground/background colors for notes edited within the past
+ month.
+
+ Default values: ``brown/default``
+
+.. confval:: clr_note_title_year_fg
+
+.. confval:: clr_note_title_year_bg
+
+ The foreground/background colors for notes edited within the past
+ year.
+
+ Default values: ``light blue/default``
+
+.. confval:: clr_note_title_ancient_fg
+
+.. confval:: clr_note_title_ancient_bg
+
+ The foreground/background colors for notes last edited more than one
+ year ago.
+
+ Default values: ``light blue/default``
+
+.. confval:: clr_note_date_fg
+
+.. confval:: clr_note_date_bg
+
+ The foreground/background colors for the note date (i.e. the ``%D``
+ portion of :confval:`cfg_format_note_title`).
+
+ Default values: ``dark blue/default``
+
+.. confval:: clr_note_flags_fg
+
+.. confval:: clr_note_flags_bg
+
+ The foreground/background colors for the note flags (i.e., the ``%F``
+ portion of :confval:`cfg_format_note_title`).
+
+ Default values: ``dark magenta/default``
+
+.. confval:: clr_note_category_fg
+
+.. confval:: clr_note_category_bg
+
+ The foreground/background colors for the note category (i.e., the
+ ``%T`` portion of :confval:`cfg_format_note_title`).
+
+ Default values: ``dark red/default``
+
+.. confval:: clr_note_content_fg
+
+.. confval:: clr_note_content_bg
+
+ The foreground/background colors for the note content as displayed
+ in the internal pager.
+
+ Default values: ``default/default``
+
+.. confval:: clr_note_content_focus_fg
+
+.. confval:: clr_note_content_focus_bg
+
+ The foreground/background colors for focused content within the
+ internal pager.
+
+ Default values: ``white/light red``
+
+.. confval:: clr_note_content_old_fg
+
+.. confval:: clr_note_content_old_bg
+
+ The foreground/background colors for old note content as displayed
+ within the internal pager.
+
+ Default values: ``yellow/dark gray``
+
+.. confval:: clr_note_content_old_focus_fg
+
+.. confval:: clr_note_content_old_focus_bg
+
+ The foreground/background colors for old note focused content as
+ displayed within the internal pager.
+
+ Default values: ``white/light red``
+
+.. confval:: clr_help_focus_fg
+
+.. confval:: clr_help_focus_bg
+
+ The foreground/background colors for focused content in the help
+ screen.
+
+ Default values: ``white/light red``
+
+.. confval:: clr_help_header_fg
+
+.. confval:: clr_help_header_bg
+
+ The foreground/background colors for header content in the help
+ screen.
+
+ Default values: ``dark blue/default``
+
+.. confval:: clr_help_config_fg
+
+.. confval:: clr_help_config_bg
+
+ The foreground/background colors for configuration option name (e.g.,
+ ``clr_help_focus_bg``) in the help screen.
+
+ Default values: ``dark green/default``
+
+.. confval:: clr_help_value_fg
+
+.. confval:: clr_help_value_bg
+
+ The foreground/background colors for the value of a configuration
+ option as set in ``config``.
+
+ Default values: ``dark red/default``
+
+.. confval:: clr_help_descr_fg
+
+.. confval:: clr_help_descr_bg
+
+ The foreground/background colors for the configuration options
+ description in the help screen.
+
+ Default values: ``default/default``
+
+Examples
+--------
+
+At the very least, the following example ``config`` will get you going
+(using your account information):
+
+.. code-block:: ini
+
+ [nncli]
+ cfg_nn_username = lebowski@thedude.com
+ cfg_nn_password = nihilist
+ cfg_nn_host = nextcloud.thedude.com
+
+Start nncli with no arguments which starts the console GUI mode. nncli
+will begin to sync your existing notes and you'll see log messages at
+the bottom of the console. You can view these log messages at any time
+by pressing the ``l`` key.
+
+View the help by pressing ``h``. Here you'll see all the keybinds and
+configuration items. The middle column shows the config name that can be
+used in your ``config`` to override the default setting.
+
+See example configuration file below for more notes.
+
+.. code-block:: ini
+
+ [nncli]
+ cfg_nn_username = lebowski@thedude.com
+ cfg_nn_password = nihilist
+ cfg_nn_host = nextcloud.thedude.com
+
+ ; as an alternate to cfg_nn_password you could use the following config item
+ ; any shell command can be used; its stdout is used for the password
+ ; trailing newlines are stripped for ease of use
+ ; note: if both password config are given, cfg_nn_password will be used
+ cfg_nn_password_eval = gpg --quiet --for-your-eyes-only --no-tty --decrypt ~/.nncli-pass.gpg
+
+ ; see http://urwid.org/manual/userinput.html for examples of more key
+ ; combinations
+ kb_edit_note = space
+ kb_page_down = ctrl f
+
+ ; note that values must not be quoted
+ clr_note_focus_bg = light blue
+
+ ; if this editor config value is not provided, the $EDITOR env var will be
+ ; used instead
+ ; warning: if neither $EDITOR or cfg_editor is set, it will be impossible to
+ ; edit notes
+ cfg_editor = nvim
+
+ ; alternatively, {fname} and/or {line} are substituted with the filename and
+ ; current line number in nncli's pager.
+ ; If {fname} isn't supplied, the filename is simply appended.
+ ; examples:
+ cfg_editor = nvim {fname} +{line}
+ cfg_editor = nano +{line}
+
+ ; this is also supported for the pager:
+ cfg_pager = less -c +{line} -N {fname}
diff --git a/docs/source/index.rst b/docs/source/index.rst
new file mode 100644
index 0000000..6270e93
--- /dev/null
+++ b/docs/source/index.rst
@@ -0,0 +1,23 @@
+.. nncli documentation master file, created by
+ sphinx-quickstart on Thu Aug 30 11:10:44 2018.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+NextCloud Notes Command Line Interface
+======================================
+
+.. include:: ../../README.rst
+
+.. toctree::
+ :maxdepth: 2
+ :caption: Contents:
+
+ configuration
+ usage
+
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`search`
diff --git a/docs/source/usage.rst b/docs/source/usage.rst
new file mode 100644
index 0000000..7502ecd
--- /dev/null
+++ b/docs/source/usage.rst
@@ -0,0 +1,356 @@
+Usage
+=====
+
+.. program:: nncli
+
+When ``nncli`` is run without any options or arguments an interactive
+console GUI will appear. The behavior of this interface is highly
+configurable (see: :ref:`configuration`).
+
+In addition to this default behavior, there are several options
+available when calling ``nncli`` without a subcommand.
+
+.. option:: --help, -h
+
+Displays a brief decription of the ``nncli`` options and subcommands.
+
+.. option:: --version, -V
+
+Displays the version information.
+
+Also available when calling ``nncli`` by itself is the ``--config``
+option, for which see: :ref:`general-options`.
+
+Subcommands
+-----------
+
+There are a variety of subcommands available from the command line when
+using ``nncli``. The intent is for these subcommands to enable
+scripting against your NextCloud Notes database. The subcommands are:
+
+- sync
+
+- list
+
+- export
+
+- dump
+
+- create
+
+- import
+
+- edit
+
+- delete
+
+- (un)favorite
+
+- cat {get,set,rm}
+
+These subcommands and the options available to them are described below.
+
+.. _general-options:
+
+General Subcommand Options
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Several ``nncli`` options apply to multiple subcommands. They are:
+
+.. option:: --verbose, -v
+
+Print verbose logging information to ``stdout``
+
+.. option:: --nosync, -n
+
+Operate only on the local notes cache. Do not reach out to the server.
+
+.. option:: --regex, -r
+
+For subcommands that accept a search string, treat the search string as
+a regular expression.
+
+.. option:: --key, -k
+
+The ID of the note to operate on. This option is required for many of
+the subcommands.
+
+.. option:: --config, -c
+
+Specify the config file to read from. This option is only required to
+override the default location (see: :ref:`config-file`).
+
+nncli sync
+~~~~~~~~~~
+
+.. program:: nncli sync
+
+Command format: ``nncli sync``
+
+Performs a full, bi-directional sync between the local notes cache and
+the NextCloud Notes server. There are no available options for this
+subcommand.
+
+- Available options: None
+
+- Arguments: None
+
+nncli list
+~~~~~~~~~~
+
+.. program:: nncli list
+
+Command format: ``nncli list [search_string]``
+
+List notes by ID, flags, and title. Flags indicate whether the note has
+been modified locally (``X``), and/or if it is marked as a favorite
+(``*``).
+
+- Available options:
+
+ - ``--regex, -r`` See :ref:`general-options`
+
+- Arguments:
+
+ - ``search_string`` Optional. A search term used to refine the search.
+
+nncli export
+~~~~~~~~~~~~
+
+.. program:: nncli export
+
+Command format: ``nncli export [search_string]``
+
+Exports notes in raw, JSON format. The JSON format is a superset of the
+format outlined in the NextCloud Notes API specification with
+information added for managing the local notes cache. Note that nncli
+still stores all the notes data in the directory specified by
+``cfg_db_path``, so for easy backups, it may be easier/quicker to simply
+backup this entire directory.
+
+- Available options:
+
+ - :ref:`general-options`
+
+ - ``--regex, -r`` Mutually exclusive with ``--key``
+
+ - ``--key, -k``
+
+- Arguments:
+
+ - ``search_string`` Required if ``--regex`` is specified. A search
+ term used to refine the search.
+
+Example:
+
+.. code-block:: sh
+
+ # export a single note by id
+ nncli -k somekeyid export
+
+ # export all notes
+ nncli export
+
+ # export notes matching search string
+ nncli [-r] export some search keywords or regex
+
+nncli dump
+~~~~~~~~~~
+
+.. program:: nncli dump
+
+Command format: ``nncli dump [search_string]``
+
+Prints notes to ``stdout``. The printed format is the text of the note
+preceeded by a header displaying information about the note title, key,
+modified date, category, and flags. Flags indicate whether the note has
+been modified locally (``X``), and/or if it is marked as a favorite
+(``*``).
+
+- Available options:
+
+ - :ref:`general-options`
+
+ - ``--regex, -r`` Mutually exclusive with ``--key``
+
+ - ``--key, -k``
+
+- Arguments:
+
+ - ``search_string`` Required if ``--regex`` is specified. A search
+ term used to refine the search.
+
+nncli create
+~~~~~~~~~~~~
+
+.. program:: nncli create
+
+Command format: ``nncli create [-]``
+
+Create a note. Without arguments, this command will open your configured
+editor. The note syncs to the server after the editor is closed.
+
+- Available options: None
+
+- Arguments:
+
+ - `-` Optional. If specified, the note content is read from ``stdin``.
+
+Example:
+
+.. code-block:: sh
+
+ # create a new note and open in editor
+ nncli create
+
+ # create a new note with contents of stdin
+ echo 'hi' | nncli create -
+
+nncli import
+~~~~~~~~~~~~
+
+.. program:: nncli import
+
+Command format: ``nncli import [-]``
+
+Import a JSON-formatted note. nncli can import notes from raw json data
+(via stdin or editor). Allowed fields are ``content``, ``category``,
+``favorite``, and ``modified``.
+
+- Available options: None
+
+- Arguments:
+
+ - ``-`` Optional. If specified, the note content is read from ``stdin``.
+
+Example:
+
+.. code-block:: none
+
+ echo '{"category":"testing","content":"New note!"}' | nncli import -
+
+nncli edit
+~~~~~~~~~~
+
+.. program:: nncli edit
+
+Command format: ``nncli -k <key> edit``
+
+Open the note specified by ``<key>`` in the configured editor. The note
+syncs to the server after the editor is saved and closed.
+
+- Available options:
+
+ - ``--key, -k`` Required. See :ref:`general-options`
+
+- Arguments: None
+
+nncli delete
+~~~~~~~~~~~~
+
+.. program:: nncli delete
+
+Command format: ``nncli -k <key> delete``
+
+Delete the note specified by ``<key>``.
+
+- Available options:
+
+ - ``--key, -k`` Required. See :ref:`general-options`
+
+- Arguments: None
+
+nncli favorite
+~~~~~~~~~~~~~~
+
+.. program:: nncli favorite
+
+Command format: ``nncli -k <key> favorite|unfavorite``
+
+Favorite (or unfavorite) the note specified by ``<key>``.
+
+- Available options:
+
+ - ``--key, -k`` Required. See :ref:`general-options`
+
+- Arguments: None
+
+nncli cat
+~~~~~~~~~
+
+.. program:: nncli cat
+
+Command format: ``nncli -k <key> cat get|set|rm``
+
+Read or modify a note category from the command line.
+
+- Available options:
+
+ - ``--key, -k`` Required. See :ref:`general-options`
+
+- Arguments:
+
+ - ``get`` Get the note category
+
+ - ``set`` Set the note category
+
+ - ``rm`` Remove the note category
+
+Example:
+
+.. code-block:: sh
+
+ # Retrieve note category (e.g. "category1")
+ nncli -k somekeyid cat get
+ # Returns "category1"
+
+ # Add a category to a note, overwriting any existing one
+ nncli -k somekeyid cat set "category3"
+ # Now tagged as "category3"
+
+ # Remove a category from a note
+ nncli -k somekeyid cat rm
+ # Note now has no category
+
+Console GUI Usage
+-----------------
+
+.. index:: single: searching
+
+Searching
+~~~~~~~~~
+
+nncli supports two styles of search strings. First is a Google style
+search string and second is a Regular Expression.
+
+A Google style search string is a group of tokens (separated by spaces)
+with an implied *AND* between each token. This style search is case
+insensitive. For example:
+
+.. code-block:: none
+
+ /category:category1 category:category2 word1 "word2 word3" category:category3
+
+Regular expression searching also supports the use of flags (currently
+only case-insensitive) by adding a final forward slash followed by the
+flags. The following example will do a case-insensitive search for
+``something``:
+
+.. code-block:: none
+
+ (regex) /something/i
+
+.. index:: single: modelines
+
+Modelines
+~~~~~~~~~
+
+Advanced text editors usually tailor their behavior based on the file
+type being edited. For such editors, notes opened through nncli should
+be treated as Markdown by default. However, you can change this
+on a per-note basis through the use of modelines. In Vim, for instance,
+a modeline is a comment line conforming to the pattern below::
+
+ :: vim: ft=rst
+
+Now when you edit this note Vim will automatically load the rst plugin.
diff --git a/nncli b/nncli
deleted file mode 100755
index 51128c4..0000000
--- a/nncli
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/usr/bin/env python3
-#
-# The MIT License (MIT)
-#
-# Copyright (c) 2018 Daniel Moch
-#
-# 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.
-#
-
-#
-# ** The MIT License **
-#
-# Copyright (c) 2014 Eric Davis (edavis@insanum.com)
-#
-# 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.
-#
-# Dude... just buy me a beer. :-)
-#
-
-from nnotes_cli import nncli
-
-if __name__ == '__main__':
- nncli.main()
-
diff --git a/nncli/__init__.py b/nncli/__init__.py
new file mode 100644
index 0000000..83d46a5
--- /dev/null
+++ b/nncli/__init__.py
@@ -0,0 +1,4 @@
+# -*- encoding: utf-8 -*-
+"""NextCloud Notes Command Line Interface"""
+
+__version__ = '0.2.0'
diff --git a/nncli/__main__.py b/nncli/__main__.py
new file mode 100644
index 0000000..d96036a
--- /dev/null
+++ b/nncli/__main__.py
@@ -0,0 +1,6 @@
+# -*- encoding: utf-8 -*-
+"""nncli main module"""
+import nncli.nncli
+
+if __name__ == '__main__':
+ nncli.nncli.main()
diff --git a/nnotes_cli/clipboard.py b/nncli/clipboard.py
index 8ef7c86..84ef1fa 100644
--- a/nnotes_cli/clipboard.py
+++ b/nncli/clipboard.py
@@ -1,7 +1,8 @@
+# -*- encoding: utf-8 -*-
+
import os
from distutils import spawn
-
class Clipboard(object):
def __init__(self):
self.copy_command = self.get_copy_command()
diff --git a/nnotes_cli/config.py b/nncli/config.py
index 31b5172..4e8cc96 100644
--- a/nnotes_cli/config.py
+++ b/nncli/config.py
@@ -1,29 +1,4 @@
-#
-# The MIT License (MIT)
-#
-# Copyright (c) 2018 Daniel Moch
-#
-# 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.
-#
-
-# Copyright (c) 2014 Eric Davis
-# Licensed under the MIT License
+# -*- encoding: utf-8 -*-
import os, sys, urwid, collections, configparser, subprocess
@@ -296,4 +271,3 @@ class Config:
def get_color_descr(self, name):
return self.colors[name][1]
-
diff --git a/nnotes_cli/nextcloud_note.py b/nncli/nextcloud_note.py
index f26fb33..5232a49 100644
--- a/nnotes_cli/nextcloud_note.py
+++ b/nncli/nextcloud_note.py
@@ -1,41 +1,4 @@
-#
-# The MIT License (MIT)
-#
-# Copyright (c) 2018 Daniel Moch
-#
-# 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.
-#
-
-# Copyright (c) 2014 Eric Davis
-# This file is *slightly* modified from simplynote.py.
-
# -*- coding: utf-8 -*-
-"""
- nextcloud_note.py
- ~~~~~~~~~~~~~~
-
- Python library for accessing the NextCloud Notes API (v0.2)
-
- Modified from simplnote.py
- :copyright: (c) 2011 by Daniel Schauenberg
- :license: MIT, see LICENSE for more details.
-"""
import urllib.parse
from requests.exceptions import RequestException, ConnectionError
diff --git a/nnotes_cli/nncli.py b/nncli/nncli.py
index 7ef76a6..340d3c1 100644
--- a/nnotes_cli/nncli.py
+++ b/nncli/nncli.py
@@ -1,34 +1,9 @@
-#
-# The MIT License (MIT)
-#
-# Copyright (c) 2018 Daniel Moch
-#
-# 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.
-#
-
-# Copyright (c) 2014 Eric Davis
-# Licensed under the MIT License
+# -*- encoding: utf-8 -*-
import os, sys, getopt, re, signal, time, datetime, shlex, hashlib
import subprocess, threading, logging
import copy, json, urwid, datetime
-import nnotes_cli
+import nncli
from . import view_titles, view_note, view_help, view_log, user_input
from . import utils, temp
from .config import Config
@@ -1173,17 +1148,7 @@ Usage:
sys.exit(0)
def version():
- version_info = ''
- version_info += nnotes_cli.__productname__ + ' v' + \
- nnotes_cli.__version__ + "\n"
- version_info += nnotes_cli.__description__ + "\n\n"
- version_info += nnotes_cli.__copyright__ + "\n"
- version_info += "Written by " + nnotes_cli.__author__ + \
- " and others\n"
- version_info += "Licensed under the terms of the " + \
- nnotes_cli.__license__ + " license\n"
- version_info += "The latest code is available at: " + \
- nnotes_cli.__url__
+ version_info = 'nncli {}'.format(nncli.__version__)
print(version_info)
exit(0)
@@ -1338,4 +1303,3 @@ def main(argv=sys.argv[1:]):
else:
usage()
-
diff --git a/nnotes_cli/notes_db.py b/nncli/notes_db.py
index c66bedf..9c688eb 100644
--- a/nnotes_cli/notes_db.py
+++ b/nncli/notes_db.py
@@ -1,33 +1,4 @@
-#
-# The MIT License (MIT)
-#
-# Copyright (c) 2018 Daniel Moch
-#
-# 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.
-#
-
-# Copyright (c) 2014 Eric Davis
-# This file is *heavily* modified from nvpy.
-
-# nvPY: cross-platform note-taking app with simplenote syncing
-# copyright 2012 by Charl P. Botha <cpbotha@vxlabs.com>
-# new BSD license
+# -*- encoding: utf-8 -*-
import os, time, re, glob, json, copy, threading
from . import utils
@@ -675,4 +646,3 @@ class NotesDB():
self.go_cond.acquire()
self.go_cond.notify()
self.go_cond.release()
-
diff --git a/nnotes_cli/temp.py b/nncli/temp.py
index 3850f7b..5bebbe6 100644
--- a/nnotes_cli/temp.py
+++ b/nncli/temp.py
@@ -1,6 +1,4 @@
-
-# Copyright (c) 2014 Eric Davis
-# Licensed under the MIT License
+# -*- encoding: utf-8 -*-
import os, json, tempfile
diff --git a/nnotes_cli/user_input.py b/nncli/user_input.py
index 79be6a3..d956145 100644
--- a/nnotes_cli/user_input.py
+++ b/nncli/user_input.py
@@ -1,6 +1,4 @@
-
-# Copyright (c) 2014 Eric Davis
-# Licensed under the MIT License
+# -*- encoding: utf-8 -*-
import urwid
@@ -23,4 +21,3 @@ class UserInput(urwid.Edit):
else:
return super(UserInput, self).keypress(size, key)
return None
-
diff --git a/nnotes_cli/utils.py b/nncli/utils.py
index 4ad76e5..0a83c96 100644
--- a/nnotes_cli/utils.py
+++ b/nncli/utils.py
@@ -1,33 +1,4 @@
-#
-# The MIT License (MIT)
-#
-# Copyright (c) 2018 Daniel Moch
-#
-# 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.
-#
-
-# Copyright (c) 2014 Eric Davis
-# This file is *heavily* modified from nvpy.
-
-# nvPY: cross-platform note-taking app with simplenote syncing
-# copyright 2012 by Charl P. Botha <cpbotha@vxlabs.com>
-# new BSD license
+# -*- encoding: utf-8 -*-
import datetime, random, re
diff --git a/nnotes_cli/view_help.py b/nncli/view_help.py
index 2593a08..4dc247e 100644
--- a/nnotes_cli/view_help.py
+++ b/nncli/view_help.py
@@ -1,6 +1,4 @@
-
-# Copyright (c) 2014 Eric Davis
-# Licensed under the MIT License
+# -*- encoding: utf-8 -*-
import re, urwid
@@ -125,4 +123,3 @@ class ViewHelp(urwid.ListBox):
def keypress(self, size, key):
return key
-
diff --git a/nnotes_cli/view_log.py b/nncli/view_log.py
index cc0f0a5..a529bf7 100644
--- a/nnotes_cli/view_log.py
+++ b/nncli/view_log.py
@@ -1,6 +1,4 @@
-
-# Copyright (c) 2014 Eric Davis
-# Licensed under the MIT License
+# -*- encoding: utf-8 -*-
import urwid
@@ -47,4 +45,3 @@ class ViewLog(urwid.ListBox):
def keypress(self, size, key):
return key
-
diff --git a/nnotes_cli/view_note.py b/nncli/view_note.py
index a06e76b..8732a50 100644
--- a/nnotes_cli/view_note.py
+++ b/nncli/view_note.py
@@ -1,6 +1,4 @@
-
-# Copyright (c) 2014 Eric Davis
-# Licensed under the MIT License
+# -*- encoding: utf-8 -*-
import time, urwid
from . import utils
diff --git a/nnotes_cli/view_titles.py b/nncli/view_titles.py
index fac4c3a..58ccebf 100644
--- a/nnotes_cli/view_titles.py
+++ b/nncli/view_titles.py
@@ -1,6 +1,4 @@
-
-# Copyright (c) 2014 Eric Davis
-# Licensed under the MIT License
+# encoding: utf-8 -*-
import re, time, datetime, urwid, subprocess
from . import utils, view_note
@@ -189,4 +187,3 @@ class ViewTitles(urwid.ListBox):
def keypress(self, size, key):
return key
-
diff --git a/nnotes_cli/__init__.py b/nnotes_cli/__init__.py
deleted file mode 100644
index 9908156..0000000
--- a/nnotes_cli/__init__.py
+++ /dev/null
@@ -1,17 +0,0 @@
-try:
- from . import version
- __version__ = version.version
-except ImportError:
- try:
- from setuptools_scm import get_version
- __version__ = get_version(root='..', relative_to=__file__)
- except:
- __version__ = '??-dev'
-
-__productname__ = 'nncli'
-__copyright__ = "Copyright (c) 2018 Daniel Moch"
-__author__ = "Daniel Moch"
-__author_email__ = "daniel@danielmoch.com"
-__description__ = "NextCloud Notes Command Line Interface"
-__url__ = "https://github.com/djmoch/nncli"
-__license__ = "MIT"
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..0be3515
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,24 @@
+[build-system]
+requires = ["flit"]
+build-backend = "flit.buildapi"
+
+[tool.flit.metadata]
+module = "nncli"
+author = "Daniel Moch"
+author-email = "daniel@danielmoch.com"
+home-page = "https://github.com/djmoch/nncli"
+description-file = "README.rst"
+requires = ["urwid", "requests", "appdirs"]
+classifiers = ["License :: OSI Approved :: MIT License",
+ "Development Status :: 4 - Beta",
+ "Environment :: Console :: Curses",
+ "Intended Audience :: End Users/Desktop",
+ "License :: OSI Approved :: MIT License",
+ "Programming Language :: Python :: 3 :: Only"]
+requires-python = ">=3"
+
+[tool.flit.metadata.requires-extra]
+dev = ["pipenv"]
+
+[tool.flit.scripts]
+nncli = "nncli.nncli:main"
diff --git a/pytest.ini b/pytest.ini
new file mode 100644
index 0000000..86d57a4
--- /dev/null
+++ b/pytest.ini
@@ -0,0 +1,2 @@
+[pytest]
+mock_use_standalone_module = true
diff --git a/setup.cfg b/setup.cfg
deleted file mode 100644
index b0bd258..0000000
--- a/setup.cfg
+++ /dev/null
@@ -1,12 +0,0 @@
-[aliases]
-test=pytest
-
-[tool:pytest]
-testpaths = tests
-addopts = --cov=nnotes_cli --cov-report=term-missing
-
-[yapf]
-coalesce_brackets = true
-dedent_closing_brackets = true
-space_between_ending_comma_and_closing_bracket = false
-split_arguments_when_comma_terminated = true
diff --git a/setup.py b/setup.py
deleted file mode 100644
index 9391552..0000000
--- a/setup.py
+++ /dev/null
@@ -1,64 +0,0 @@
-#
-# The MIT License (MIT)
-#
-# Copyright (c) 2018 Daniel Moch
-#
-# 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.
-#
-
-# Copyright (c) 2014 Eric Davis
-# Licensed under the MIT License
-
-from setuptools import setup
-import nnotes_cli
-
-deps = ['urwid', 'requests', 'appdirs']
-test_deps = ['pytest', 'pytest-cov', 'pytest-runner', 'pytest-mock']
-
-with open("README.md", "r") as fh:
- long_description = fh.read()
-
-setup(
- name=nnotes_cli.__productname__,
- description=nnotes_cli.__description__,
- long_description=long_description,
- long_description_content_type="text/markdown",
- author=nnotes_cli.__author__,
- author_email=nnotes_cli.__author_email__,
- url=nnotes_cli.__url__,
- license=nnotes_cli.__license__,
- requires=deps,
- install_requires=deps,
- tests_require=test_deps,
- use_scm_version= {'write_to': 'nnotes_cli/version.py'},
- setup_requires=['setuptools_scm'],
- packages=['nnotes_cli'],
- entry_points={
- 'console_scripts': [
- 'nncli = nnotes_cli.nncli:main'
- ]
- },
- classifiers=[
- 'Development Status :: 4 - Beta',
- 'Environment :: Console :: Curses',
- 'Intended Audience :: End Users/Desktop',
- 'License :: OSI Approved :: MIT License',
- 'Programming Language :: Python :: 3 :: Only',
- ],
-)
diff --git a/tests/test_config.py b/tests/test_config.py
index 75fe1e9..0e6ffe1 100644
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -1,33 +1,13 @@
-#
-# The MIT License (MIT)
-#
-# Copyright (c) 2018 Daniel Moch
-#
-# 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.
-#
+# -*- encoding: utf-8 -*-
+
import os
import sys
-from nnotes_cli.config import Config
+from nncli.config import Config
from pytest import raises
-def test_init():
+def test_init(mocker):
+ mocker.patch('subprocess.check_output')
config = Config()
if sys.platform == 'linux':
diff --git a/tests/test_nncli.py b/tests/test_nncli.py
index 394135a..78d213b 100644
--- a/tests/test_nncli.py
+++ b/tests/test_nncli.py
@@ -1,278 +1,279 @@
-#
-# The MIT License (MIT)
-#
-# Copyright (c) 2018 Daniel Moch
-#
-# 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.
-#
+# -*- encoding: utf-8 -*-
+
import logging
import os
import pytest
import shutil
from logging.handlers import RotatingFileHandler
-from nnotes_cli.nncli import nncli
+import nncli.nncli
+@pytest.fixture
def mock_nncli(mocker):
mocker.patch('logging.getLogger')
- mocker.patch('nnotes_cli.config.Config')
- mocker.patch('nnotes_cli.notes_db.NotesDB')
+ mocker.patch('nncli.nncli.NotesDB')
mocker.patch('os.mkdir')
mocker.patch.object(RotatingFileHandler, '_open')
+ mocker.patch('subprocess.check_output')
+
+def mock_get_config(mocker, return_list):
+ mocker.patch.object(
+ nncli.nncli.Config,
+ 'get_config',
+ new=mocker.MagicMock(side_effect=return_list)
+ )
def assert_initialized():
- logging.getLogger.assert_called_once()
+ assert logging.getLogger.call_count == 2
RotatingFileHandler._open.assert_called_once()
- assert os.mkdir.call_count == 2
+ os.mkdir.assert_called_once()
-@pytest.mark.parametrize('mock_nncli', [mock_nncli])
def test_init_no_tempdir(mocker, mock_nncli):
- mock_nncli(mocker)
-
- with open('test_cfg', 'w') as config_file:
- config_file.write('[nncli]\n')
- config_file.write('cfg_db_path=duh')
-
- nn = nncli(False, config_file='test_cfg')
+ mock_get_config(mocker, ['what', '', 'duh', 'duh', 'duh'])
+ nn = nncli.nncli.nncli(False)
assert_initialized()
assert nn.tempdir == None
os.mkdir.assert_called_with('duh')
- os.remove('test_cfg')
-
-@pytest.mark.parametrize('mock_nncli', [mock_nncli])
def test_init(mocker, mock_nncli):
- mock_nncli(mocker)
-
- with open('test_cfg', 'w') as config_file:
- config_file.write('[nncli]\n')
- config_file.write('cfg_tempdir=blah\n')
- config_file.write('cfg_db_path=duh')
-
- nn = nncli(False, config_file='test_cfg')
+ mock_get_config(mocker, ['what', 'blah', 'duh', 'duh', 'duh'])
+ nn = nncli.nncli.nncli(False)
assert_initialized()
assert nn.tempdir == 'blah'
- os.remove('test_cfg')
-
-@pytest.mark.parametrize('mock_nncli', [mock_nncli])
def test_init_notesdb_fail(mocker, mock_nncli):
- os.mkdir('duh')
- mock_nncli(mocker)
-
- with open('duh/1.json', 'w') as bad_file:
- bad_file.write('bad_json_data')
-
- with open('test_cfg', 'w') as config_file:
- config_file.write('[nncli]\n')
- config_file.write('cfg_db_path=duh')
-
+ mock_get_config(mocker, ['what', 'blah', 'duh', 'duh', 'duh'])
+ mocker.patch('nncli.nncli.NotesDB',
+ new=mocker.MagicMock(side_effect=SystemExit)
+ )
with pytest.raises(SystemExit):
- nn = nncli(False, config_file='test_cfg')
-
- shutil.rmtree('duh')
+ nn = nncli.nncli.nncli(False)
-@pytest.mark.parametrize('mock_nncli', [mock_nncli])
def test_get_editor(mocker, mock_nncli):
- mock_nncli(mocker)
-
- with open('test_cfg', 'w') as config_file:
- config_file.write('[nncli]\n')
- config_file.write('cfg_db_path=duh')
- config_file.write('cfg_editor=vim')
-
- nn = nncli(False, config_file='test_cfg')
+ mock_get_config(mocker, ['what', 'blah', 'duh', 'duh', 'duh', 'vim', ''])
+ nn = nncli.nncli.nncli(False)
assert_initialized()
assert nn.get_editor() == 'vim'
+ assert nn.get_editor() == None
- os.remove('test_cfg')
-
-@pytest.mark.parametrize('mock_nncli', [mock_nncli])
-def test_no_editor(mocker, mock_nncli):
- mock_nncli(mocker)
-
- with open('test_cfg', 'w') as config_file:
- config_file.write('[nncli]\n')
- config_file.write('cfg_db_path=duh')
-
- nn = nncli(False, config_file='test_cfg')
- nn.config.configs['editor'] = ['']
+def test_get_pager(mocker, mock_nncli):
+ mock_get_config(mocker, ['what', 'blah', 'duh', 'duh', 'duh', 'less', ''])
+ nn = nncli.nncli.nncli(False)
assert_initialized()
+ assert nn.get_editor() == 'less'
assert nn.get_editor() == None
- os.remove('test_cfg')
-
-def test_get_pager():
- pass
-
-def test_get_diff():
- pass
+def test_get_diff(mocker, mock_nncli):
+ mock_get_config(mocker, ['what', 'blah', 'duh', 'duh', 'duh', 'diff', ''])
+ nn = nncli.nncli.nncli(False)
+ assert_initialized()
+ assert nn.get_editor() == 'diff'
+ assert nn.get_editor() == None
-def test_exec_cmd_on_note():
- pass
+@pytest.mark.skip
+def test_exec_cmd_on_note(mocker, mock_nncli):
+ mocker.patch.object(
+ 'nncli.nncli.nncli',
+ get_editor,
+ new=mocker.MagicMock(return_value='vim'))
+ mocker.patch('nncli.temp.tempfile_create')
+@pytest.mark.skip
def test_exec_diff_on_note():
pass
+@pytest.mark.skip
def test_gui_header_clear():
pass
+@pytest.mark.skip
def test_gui_header_set():
pass
+@pytest.mark.skip
def test_gui_header_get():
pass
+@pytest.mark.skip
def test_gui_header_focus():
pass
+@pytest.mark.skip
def test_gui_footer_log_clear():
pass
+@pytest.mark.skip
def test_gui_footer_log_set():
pass
+@pytest.mark.skip
def test_gui_footer_log_get():
pass
+@pytest.mark.skip
def test_gui_footer_input_clear():
pass
+@pytest.mark.skip
def test_gui_footer_input_set():
pass
+@pytest.mark.skip
def test_gui_footer_input_get():
pass
+@pytest.mark.skip
def test_gui_footer_focus_input():
pass
+@pytest.mark.skip
def test_gui_body_clear():
pass
+@pytest.mark.skip
def test_gui_body_set():
pass
+@pytest.mark.skip
def test_gui_body_get():
pass
+@pytest.mark.skip
def test_gui_body_focus():
pass
+@pytest.mark.skip
def test_log_timeout():
pass
+@pytest.mark.skip
def test_log():
pass
+@pytest.mark.skip
def test_gui_update_view():
pass
+@pytest.mark.skip
def test_gui_update_status_bar():
pass
+@pytest.mark.skip
def test_gui_switch_frame_body():
pass
+@pytest.mark.skip
def test_delete_note_callback():
pass
+@pytest.mark.skip
def test_gui_yes_no_input():
pass
+@pytest.mark.skip
def test_gui_search_input():
pass
+@pytest.mark.skip
def test_gui_category_input():
pass
+@pytest.mark.skip
def test_gui_pipe_input():
pass
+@pytest.mark.skip
def test_gui_frame_keypress():
pass
+@pytest.mark.skip
def test_gui_init_view():
pass
+@pytest.mark.skip
def test_gui_clear():
pass
+@pytest.mark.skip
def test_gui_reset():
pass
+@pytest.mark.skip
def test_gui_stop():
pass
+@pytest.mark.skip
def test_gui():
pass
+@pytest.mark.skip
def test_cli_list_notes():
pass
+@pytest.mark.skip
def test_cli_note_dump():
pass
+@pytest.mark.skip
def test_cli_dump_notes():
pass
+@pytest.mark.skip
def test_cli_note_create():
pass
+@pytest.mark.skip
def test_cli_note_import():
pass
+@pytest.mark.skip
def test_cli_note_export():
pass
+@pytest.mark.skip
def test_cli_export_notes():
pass
+@pytest.mark.skip
def test_cli_note_edit():
pass
+@pytest.mark.skip
def test_cli_note_delete():
pass
+@pytest.mark.skip
def test_cli_note_favorite():
pass
+@pytest.mark.skip
def test_cli_note_category_get():
pass
+@pytest.mark.skip
def test_cli_note_category_set():
pass
+@pytest.mark.skip
def test_cli_note_category_rm():
pass
+@pytest.mark.skip
def test_SIGINT_handler():
pass
+@pytest.mark.skip
def test_usage():
pass
+@pytest.mark.skip
def test_version():
pass
+@pytest.mark.skip
def test_main():
pass
+@pytest.mark.skip
def test_nncli_start():
pass
diff --git a/tests/test_version.py b/tests/test_version.py
deleted file mode 100644
index af1224a..0000000
--- a/tests/test_version.py
+++ /dev/null
@@ -1,35 +0,0 @@
-#
-# The MIT License (MIT)
-#
-# Copyright (c) 2018 Daniel Moch
-#
-# 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.
-#
-import nnotes_cli
-import pytest
-
-from nnotes_cli import version
-from setuptools_scm import get_version
-
-@pytest.mark.skip(reason="test_version will fail outside of a Git repo")
-def test_version():
- vers = get_version(root="..", relative_to=__file__)
-
- assert nnotes_cli.__version__ == vers
- assert version.version == vers
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 0000000..708e7a4
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,29 @@
+[tox]
+envlist = py34, py35, py36, py37, pylint, coverage
+skipsdist = True
+
+[testenv:pylint]
+deps = pylint
+whitelist_externals = make
+commands = make lint
+
+[testenv:coverage]
+deps = pipenv
+setenv =
+ PIPENV_NO_INHERIT = 1
+ PIPENV_HIDE_EMOJIS = 1
+whitelist_externals = make
+commands =
+ make test-install
+ make coverage
+
+[testenv]
+deps = pipenv
+setenv =
+ PIPENV_NO_INHERIT = 1
+ PIPENV_HIDE_EMOJIS = 1
+whitelist_externals = make
+commands =
+ make test-install
+ make install
+ make test