summaryrefslogtreecommitdiff
path: root/doc/source
diff options
context:
space:
mode:
Diffstat (limited to 'doc/source')
-rw-r--r--doc/source/dev/contributing.rst67
-rw-r--r--doc/source/dev/index.rst17
-rw-r--r--doc/source/dev/overview.rst114
-rw-r--r--doc/source/dev/plugin.rst31
4 files changed, 225 insertions, 4 deletions
diff --git a/doc/source/dev/contributing.rst b/doc/source/dev/contributing.rst
new file mode 100644
index 00000000..ca7de049
--- /dev/null
+++ b/doc/source/dev/contributing.rst
@@ -0,0 +1,67 @@
+Contributing
+============
+
+Conventions
+-----------
+
+We don’t have a strict set of conventions, but you should respect PEP8 mostly
+(e.g. 4 spaces, class names in CamelCase and methods lowercased with
+underscores) except if it means less-readable code (80 chars is often a hassle,
+and if you look inside poezio you’ll see lots of long lines, mostly because of
+strings).
+
+As explained in the :ref:`overview`, “global” code goes in
+:file:`core.py`, tab-related code goes in :file:`tabs.py`, and ui-related code goes in
+:file:`windows.py`. There are other modules (e.g. :file:`xhtml.py`) but they do not matter
+for the application as a whole.
+
+Commit guidelines
+-----------------
+
+Commits **should** have a meaninful title (first line), and *may* have a detailed
+description below. There are of course exceptions (for example, a single-line
+commit that takes care of a typo right behind a big commit does not need to
+say ``fix a typo ("azre" → "are") in toto.py line 45454``, since the metainfos
+already take care of that.), but if you do not have commit access on the
+poezio trunk, you can still reset and commit again.
+
+
+Try to do atomic commits: since git is a DVCS, it doesn’t hurt to ``git add -p``
+and split the commit into several meaningful small commits ; on the contrary,
+it helps to track the changes on different levels.
+
+
+If you have a conflict, solve it with rebase and not merge if the fast-forwards
+do not resolve it automatically in your case. This helps to avoid creating
+useless merges (and polluting the commit history) when none is needed.
+
+.. code-block:: bash
+
+ git fetch origin
+ git rebase origin/master
+ git push origin master
+
+If your commit is related to an issue on our tracker_ (or fixes such an
+issue), you can use ``Fix #BUGID`` or ``References #BUGID`` to help with the
+tracking.
+
+
+Getting your code into poezio
+-----------------------------
+
+If you have code you want to contribute, you can:
+
+* Give us a patch and a description of what it does
+* Give us a link to a **git** repo from which we can pull
+
+The code is of course reviewed and tested a bit, but we trust the contributors
+to submit good code. If we can’t integrate the given code into poezio (if it
+crashes or has some issues), if the size is small, we may tweak it ourselves
+and integrate it, and if not, you are of course free to take our advice into
+account and submit it again.
+
+
+If you have already submitted some code and plan to do more, you can ask us
+ direct commit access on the main repo.
+
+.. _tracker: https://dev.louiz.org/project/poezio/bugs
diff --git a/doc/source/dev/index.rst b/doc/source/dev/index.rst
index 8bf674cc..aae0a6d0 100644
--- a/doc/source/dev/index.rst
+++ b/doc/source/dev/index.rst
@@ -6,16 +6,25 @@
Development documentation
=========================
-Contents:
+
+About plugins
+-------------
.. toctree::
:maxdepth: 2
plugin
events
- timed_events
- common
sleek
- theming
xep
+About Poezio
+------------
+
+.. toctree::
+
+ overview
+ contributing
+ theming
+ timed_events
+ common
diff --git a/doc/source/dev/overview.rst b/doc/source/dev/overview.rst
new file mode 100644
index 00000000..452938e6
--- /dev/null
+++ b/doc/source/dev/overview.rst
@@ -0,0 +1,114 @@
+.. _overview:
+
+Overview
+========
+
+.. note:: This is not an introduction to XMPP, but to how poezio works.
+
+
+Global overview
+---------------
+
+Poezio is an application that has three main layers, mostly separated in three
+different python modules: ``core``, ``tabs``, and ``windows``. An UML diagram of
+Poezio would be inneficient, cluttered, or incomplete, so there is none, if
+that bugs you.
+
+.. figure:: ../images/layers.png
+ :alt: Layers
+
+**Core** is mostly a “global” object containing the state of the application at
+any time, it contains the global commands, the xmpp event handlers, the list
+of open tabs, etc. Most objects in poezio have a self.core attribute
+referencing the **Core** (it’s a singleton, so there is never more than one
+instance). **Core** also contains the main loop of the application, which then
+dispatchs the I/O events (keypress) to the appropriate methods.
+
+But the main loop is not the most important thing in poezio; because it is an
+IM client, it is essentially event-driven. The event part is handled by
+SleekXMPP, which is the library we chose after moving away from xmpppy.
+
+
+**Tabs** are the second layer of poezio, but the first dealing with the UI: each
+**Tab** is a layout of several **windows**, it contains tab-specific commands,
+tab-specific keybinds, and it has methods in order for core to
+interact with it, and some methods are only proxies for the methods of a
+**window**.
+
+Example scenario: If someone presses the key PageUp, then Core will call the
+appropriate method on the current _Tab_, which will in turn, if it implements the
+method (inherited empty from the Tab class), call a scrolling method from the
+appropriate **window**.
+
+All tabs types inherit from the class **Tab**, and the tabs featuring
+chat functionnality will inherit from **ChatTab** (which inherits from **Tab**).
+
+Examples of **tabs**: MUCTab, XMLTab, RosterTab, MUCListTab, etc…
+
+Event handlers
+--------------
+
+The events handlers are registered right at the start of poezio, and then
+when a matching stanza is received, the handler is called in a separate thread
+from the main loop. The handlers are in **Core**, and then they call the
+appropriate methods in the corresponding **tabs**.
+
+Example scenario: if a message is received from a MUC, then the **Core** handler
+will identify the **Tab**, and call the relevant handler from this **Tab**, this tab
+will in turn, add the message to the buffer, which will then add it to the
+relevant **windows**.
+
+.. note:: All the _windows_ that deal with received or generated text are linked
+ to a **text_buffer**, in order to rebuild all the display lines from the
+ sources if necessary. This also enables us to have several **windows**
+ presenting the same text, even if they are not of the same size and layout.
+
+Commands and completion
+-----------------------
+
+Commands are quite straightforward: those are methods that take a string as a
+parameter, and they do stuff.
+
+From an user point of view, the methods are entered like that:
+
+.. code-block:: none
+
+ /command arg1 arg2
+
+or
+
+.. code-block:: none
+
+ /command "arg1 with spaces" arg2
+
+However, when creating a command, you wil deal with _one_ str, no matter what.
+There are utilities to deal with it (common.shell_split), but it is not always
+necessary. Commands are registered in the **commands** dictionnary of a tab
+structured as key (command name) -> tuple(command function, help string, completion).
+
+
+Completions are a bit tricky, but it’s easy once you get used to it:
+
+They take an **Input** (a _windows_ class) as a parameter, named the_input
+everywhere in the sources. To effectively have a completion, you have to call
+**the_input.auto_completion()** at the end of the function.
+
+
+.. code-block:: python
+
+ class Input(Win):
+ # …
+ def auto_completion(completion_list, after='', quote=True):
+ # …
+
+Set the input to iterate over _completion_list_ when the user hits tab, insert
+**after** after the completed item, and surround the item with double quotes or
+not.
+
+There is no method to find the current argument in the input (although the
+feature is planned), so you have to assume the current argument is the last,
+and guess it by splitting the string an checking for end-space.
+
+You can look for examples in the sources, all the possible cases are
+covered (single-argument, complex arguments with spaces, several arguments,
+etc…)
diff --git a/doc/source/dev/plugin.rst b/doc/source/dev/plugin.rst
index 7978a5e9..323a058a 100644
--- a/doc/source/dev/plugin.rst
+++ b/doc/source/dev/plugin.rst
@@ -1,6 +1,9 @@
Plugin API documentation
========================
+BasePlugin
+----------
+
.. module:: plugin
.. autoclass:: BasePlugin
@@ -34,8 +37,36 @@ The :py:class:`~PluginAPI` object is an a interface through which the :py:class:
(and inheritors) *should* go to interact with poezio. If it is not sufficient, then the ``core``
member can be used.
+PluginAPI
+---------
+
.. autoclass:: PluginAPI
:members:
:undoc-members:
+Example plugins
+---------------
+
+**Example 1:** Add a simple command that sends "Hello World!" into the conversation
+
+.. code-block:: python
+
+ class Plugin(BasePlugin):
+ def init(self):
+ self.add_command('hello', self.command_hello, "Send 'Hello World!'")
+
+ def command_hello(self, arg):
+ self.core.send_message('Hello World!')
+
+**Example 2:** Adds an event handler that sends “tg” to a groupchat when a message is received from someone named “Partauche”
+
+.. code-block:: python
+
+ class Plugin(BasePlugin):
+ def init(self):
+ self.add_event_handler('muc_msg', self.on_groupchat_message)
+
+ def on_groupchat_message(self, message, tab):
+ if message['mucnick'] == "Partauche":
+ tab.command_say('tg')