#+Title: Stack Exchange Mode for Emacs
#+Author: Sean Allred
#+Date: [2013-02-28 Thu]

# This line crashes Emacs.  Remove it for successful export.
#+INFOJS_OPT view:content

This document is largely incomplete.  All information is more than
subject to change.  As Github's =org-mode= parsing is currently
broken, it is advised that you view this document locally.

* TODO implement noweb-style references
to control the order of entanglement.  An example of how to do so has
been worked out under [[id:D365DE92-82B6-4754-98EA-26E28F1D8916][Installing]].
* Installing
:PROPERTIES:
:ID: D365DE92-82B6-4754-98EA-26E28F1D8916
:END:
- Note taken on [2013-03-01 Fri 01:04] \\
  More work to be done here.  Figure out exactly what needs to be done
  and update the high-level to do it.
Installation is automatic if done through a package manager such as
MELPA; in this case, it is unbefitting to require extra user
involvement.  But, since this is a /literate programming document/,
I'd like to explain how the process could be done manually.

If you are viewing this lovely file in Emacs but are still similarly
'eager' about using =stack-mode=, go ahead and =C-c C-c= [fn::which,
on a default installation, runs =org-babel-execute-src-block=] the
following line.  It will take care of installation for you.  You will
need to confirm execution twice if you have not configured
=org-babel-confirm-evaluate= to allow execuation of Emacs Lisp
snippets without confirmation.

#+call: $install()

(This document does not yet add the necessary files to the
=load-path=.  Please do so manually.

What we're basically going to do is this:
#+name: $install
#+begin_src emacs-lisp :noweb strip-export :results output
  (defun $d (m) (message (princ m)) (terpri))
  <<$install-tangle-buffer>>
  <<$install-move-to-load-path>>
#+end_src

oh shit

#+name: $install-tangle-buffer
#+begin_src emacs-lisp
  ($d "Tangling stack-mode files...")
  (org-babel-tangle)
  ($d "Tangling stack-mode files...done")
#+end_src

i'm dumb

#+name: $install-move-to-load-path
#+begin_src emacs-lisp
  (message "Moving source files to load-path...")
#+end_src

really dumb

#+name: $install-move-to-load-path
#+begin_src emacs-lisp
  (message "More moving...")
#+end_src

* Resources
- [[https://api.stackexchange.com/docs][SX.API v2.1]]
- [[http://stackapps.com/apps/oauth/register][StackApps Registration Page]]
- [[http://www.emacswiki.org/emacs/ModeTutorial][Creating Major Modes for Emacs]]
* Icon
Stack Exchange Mode for Emacs has no explicit use for an icon,
although standard SVG files have been gathered in =resources/= if
anyone would fancy a crack at it.

- [[file:resources/emacs.svg][Emacs icon]]
- [[file:resources/stackexchange.svg][Stack Exchange icon]]

* Stack Exchange API Version 2.1
:PROPERTIES:
:ID: DC2032C5-BC11-47E2-8DDB-34467C2BC479
:END:
Version 2.1 of the Stack Exchange API allows for read-only access (and
write-access for comments!) to the Stack Exchange network.

The Stack Exchange API uses JSON as its main method of interaction.

Available Features:

- Write methods 

(yeah, this needs to be expanded.)
** COMMENT
This is meant more as a reference for when I am (or another user is)
not online.  This is not official documentation, although I hope it is
accurate up to [2013-02-28 Thu 17:00].
* Implementation
** Conventions and Terminology
*** Code Conventions
- All functions will have `stack-network-` / `stack-comment-` /
  etc. (as appropriate) as a prefix.

- Functions which must alter the mode the user ends up in will be
  further prefixed with `do-` as to flag its impact.

- Functions with no arguments will effect its lack thereof with =()=,
  not =nil=.  (While =()= is /precisely/ the same as =nil= in Lisp
  (and more specifically, Emacs Lisp), it is convention do this.
  Failure to follow this convention may needlessly confuse potential
  contributors.

*** Document conventions
- When referring to a function using =a teletype font= and the first
  character is a dash, apply the appropriate prefix,
  e.g. =-do-enter-site= --> =stack-network-do-enter-site=.  It becomes
  tedious to read (not to mention to write!) these functions and
  variables involved in the same package/section so repetitively.

- When explaining a snippet of code, the related code block must be
  directly beneath or above the explanation.  Blank lines should only
  be used to make logical distinctions in the document.
  - except in special circumstances, like keymap code.


*** Terminology of Emacs Lisp
It is expected that the reader has a basic knowledge of Lisp in
general.  However, there are more than a few terms in this document
which are particularly important to Emacs Lisp programming, and are a
bit of research to find adequate definitions for.

While there are myriad functions and symbols specific to Emacs Lisp
programming, these functions are far better documented in Emacs' own
'Info' system.  Place point on a symbol you'd like to learn about and
use =C-h f= or =C-c v= (for functions or variables, respectively) to
find out more.  (Hint: it even works in this very document!)

- a-list :: a list of conses, usually pairing a symbol with a
            description or action

** Stack Mode (Entry Point): =stack-mode=
Stack mode is /the/ major mode.  What do I mean by this?  Stack mode
is the entry point of the whole package.  There is no other way to
obtain the full, original functionality of the package without first
running =M-x stack-mode=.  Stack Mode is the only mode available
interactively.  It is a dispatcher that decides, based on user
preferences, how the whole system shall behave.  It provides the basic
framework upon which the rest of the package is built.  Thus, there
are a few packages that it itself requires:
#+begin_src emacs-lisp :tangle elisp/stack-mode.el
  ;; stack-mode.el starts here
  
  (require 'json)
#+end_src

JSON (JavaScript Object Notation) is the standard by which we
communicate with Stack Exchange itself.  The details of this
communication has [[id:DC2032C5-BC11-47E2-8DDB-34467C2BC479][already been discussed]] so I will not repeat myself
here.  The JSON package provides many utilities for manipulating JSON
snippets within Emacs Lisp, and is required for the operation of this
package.  =json.el= is included with Emacs 24+ (and can easily be
obtained from the ELPA if missing).
#+begin_src emacs-lisp :tangle elisp/stack-mode.el
  (require 'request)
#+end_src

This package also requires =request.el=, a package designed to
simplify making HTTP requests.  =request.el= was written by [[http://stackoverflow.com/users/727827][SX@tkf]] and
is maintained and documented on [[http://tkf.github.com/emacs-request/manual.html][Github]]. The package is also available
for automatic install via MELPA.
#+begin_src emacs-lisp :tangle elisp/stack-mode.el
    (defgroup stack-exchange
      nil
      "Stack Exchange mode."
      :group 'environment)
#+end_src

Simply put, =defgroup= defines a customization group for the graphical
interface within Emacs.  Since it pulls all of the customizable
settings together and how to customize them, it is also useful as a
'wordbank' of sorts for customizing the package manually.  Every
customizable variable in the entire package is listed here.

Every mode needs a hook, so we here define one.  This hook is run
/after/ stack-mode is finished loading (when called interactively or
from Emacs Lisp).
#+begin_src emacs-lisp :tangle elisp/stack-mode.el
  (defvar stack-mode-hook nil)
#+end_src

In addition to a hook, most if not all major modes define their own
keymap.  Stack mode as a whole is no exception, but remembering the
nature of =stack-mode= as a dispatcher, a keymap seems out of place
here.  As such, the official keymap for =stack-mode= defines all keys
to be nil except those that are necessary for the smooth use of Emacs
as an operating system.  Such necessary keystrokes include =C-g=,
=M-x=, and others.
#+begin_src emacs-lisp :tangle elisp/stack-mode.el
  (defvar stack-mode-map
    (let ((map (make-sparse-keymap)))
      map)
    "Keymap for Stack Exchange major mode.  This keymap is not
    used.")
#+end_src

All that is left to do now is to define each customizable variable and
load all of the child modes.  We will define the variables later, and
they will be placed in this file.  We do this via =require=.
#+begin_src emacs-lisp :tangle elisp/stack-mode.el
  (require 'stack-network-mode)
#+end_src

We are done here, and =stack-mode= is provided to the user.
#+begin_src emacs-lisp :tangle elisp/stack-mode.el
  (provide 'stack-mode)
  
  ;; stack-mode.el ends here
#+end_src

For features that require unsupported write access, the message shall
be displayed: "Version <api-version> of the Stack Exchange API does
not support this action."  The functions shall exist (along with their
keymaps), but the functionality will be replaced by the display of
such a message.

When I say minor mode, I may mean a major mode mostly based off of
another mode, as these functions don't make any sense in any other
context.

At all times, the percentage of API requests left can be displayed in
the modeline according to the customizable variable (nil|t)
=stack-display-API-requests-in-modeline= and shall turn red (if
activated) when use exceeds =stack-display-API-color-threshold= (a
float in [0, 1], where 0 never changes the color).

** Network Mode: =stack-network-mode=
Network mode is a major mode (derived from =special-mode=) that
defines functions and binds keys useful for browsing and organizing
sites in the Stack Exchange network.  Since it is an integrated part
of =stack-mode= and dispatches to several sibling modes, it is
imperative that =stack-mode= (and all of its child modes) be available
upon entering =stack-network-mode=.  (For the purposes of testing,
=(require 'stack-mode)= has been commented out to avoid =load-path=
issues.  (I'm really lazy.)  In addition, a debugging function has
been added to facilitate messaging that would be useful to track down
bugs.)
#+begin_src emacs-lisp :tangle elisp/stack-network-mode.el
  ;; stack-network-mode.el starts here
  
  ;(require 'stack-mode)
  
  (defvar stack-network-display-debug-messages t)
  
  (defun stack-network-debug (format &rest args)
    (if stack-network-display-debug-messages (message format args)))
#+end_src

Here is the planned interface:
#+begin_src emacs-lisp :tangle elisp/stack-network-mode-navtest-buffer.test
  -*- stack-network -*-
  
     4 unread inbox items
     1 unread notification
  
  Favorites.............................................................
    TeX, LaTeX, and Friends                                       tex.sx
    StackOverflow                                          stackoverflow
    StackApps                                                  stackapps
    Mathematics                                                  math.sx
  
  Other Sites...........................................................
    <all other sites>
#+end_src
(While not functional, this file is intended to produce a buffer
suitable for navigation testing.  It should be de-tangled before
release.)

A mode hook is provided for customizability.  I am not sure that this
hook is automatically run or not per =special-mode=. (TODO)
#+begin_src emacs-lisp :tangle elisp/stack-network-mode.el
  (defvar stack-network-mode-hook nil)
#+end_src

*** Default Keymap
- Note taken on [2013-02-28 Thu 14:13] \\
  Issues with this are in the process of being [[http://stackoverflow.com/questions/15124824/][resolved]].  Currently,
  keybindings do not act as expected, e.g. pressing =n= will not call
  =stack-network-next-site=.

- n :: next site
- p :: previous site
- RET :: enter site into [[*Question%20Browse%20Mode:%20%3Dstack-question-browse-mode%3D][Question Browse Mode]]
- u :: profile summary (stack-profile-mode ?)
- C-u u :: profile summary for user
- i :: goto [[*Inbox%20Mode:%20%3Dstack-inbox-mode%3D][Inbox Mode]]

#+begin_src emacs-lisp :tangle elisp/stack-network-mode.el
  (defvar stack-network-mode-map
    (let ((map (make-keymap)))
      (define-key map "n"     'stack-network-next-site)
      (define-key map "p"     'stack-network-previous-site)
      (define-key map ","     'stack-network-move-site-up)
      (define-key map "."     'stack-network-move-site-down)
      (define-key map "j"     'stack-network-jump-to-bookmarks)
      (define-key map "\C-m"  'stack-network-do-enter-site) ; ret
      (define-key map "o"     'stack-network-do-enter-site)
      (define-key map "u"     'stack-network-do-profile-summary)
      (define-key map "\C-uu" 'stack-network-do-profile-summary-for-user)
      (define-key map "i"     'stack-network-do-inbox)
      (define-key map "b"     'stack-network-toggle-bookmark)
      (define-key map "\C-i"  'stack-network-display-details) ; tab
      map)
    "Keymap for Stack Exchange: Network Browser major mode")
#+end_src

*** Navigation
The primary methods of navigation =-next-site=, =-previous-site=, and
=-enter-site=.  The first two of these three do only what makes sense:
they move point up and down the list of available sites.
#+begin_src emacs-lisp :tangle elisp/stack-network-mode.el
  (defun stack-network-next-site ()
    "Move to the next site in the list."
    (interactive)
    (stack-network-debug "in next site")
    (next-line))
  
  (defun stack-network-previous-site ()
    "Move to the previous site in the list."
    (interactive)
    (stack-network-debug "in prev site")
    (previous-line))
  
  (defun stack-network-do-enter-site ()
    "Enter the site at point in another buffer."
    (interactive)
    (message "I have no idea what I'm doing")
    (stack-exchange-question-browse-mode
     (stack-network-get-site-under-point)))
#+end_src

If you look at the defintion of =-do-enter-site=, you will notice that
the heretofore undefined =-get-site-under-point= is used.  As you may
have guessed, the purpose of this function is to obtain the 'string
representation' of the Stack Exchange site upon which point currently
rests.  There is as of yet no method of retrieving this dynamically,
so a definition-style a-list is made at the very top (=stack-mode.el=)
to facilitate easy use.

#+begin_src emacs-lisp :tangle elisp/stack-mode.el
  (defvar stack-exchange-api-key-to-site-alist
    ; define
    )
#+end_src

*** Conclusion
Network mode is the highest-level mode available within =stack-mode=.
Its primary purpose is to be a dispatcher for other commands.  Since
many users reside on exactly one StackExchange site, =stack-mode=
should be configurable to support this.

#+begin_src emacs-lisp :tangle elisp/stack-network-mode.el
  (define-derived-mode stack-network-mode
    special-mode
    "SX-Network"
    "Major mode for navigating and organizing sites on the Stack
  Exchange Network.")

  (provide 'stack-network-mode)
  
  ;; stack-network-mode.el ends here
#+end_src
** Question Browse Mode: =stack-question-browse-mode=
- Note taken on [2013-02-27 Wed 15:28] \\
  Upvoting and downvoting could easily be supported in this mode, but
  shouldn't be.  How can you possibly upvote or downvote something just
  be reading the title?

This mode is buffer-read-only.

Font Lock
 - green :: answered question
 - bold red :: open bounty
 - bold :: unanswered

Sorting and Filtering
- should be able to sort

Green font-lock for answered questions, red for unanswered.

Question starring, dispatcher-y feel.

Display statistical information on top:
 - if point is on a question, display the user who asked it, their
   reputation, the last revisor, their reputation, tags, views,
   answers, accept status, and votes.  (The following example is from
   [[http://tex.stackexchange.com/questions/83970/auctex-preview-latex-and-ghostscript-emacs][one of my own questions]] retrieved [2013-02-27 Wed 15:36].)
   #+begin_example
   Full title: AUCTeX, preview-latex, and Ghostscript (Emacs)        |
        Asker: vermiculus (572)                            Bounty:  50
      Answers:  1 (Accepted)            Active: [2013-02-27 Wed 15:44]
         Tags: emacs auctex preview ghostscript
   #+end_example
 - if point is not on a question, display site trends in general
   #+begin_example
         Site: TeX, LaTeX, and Friends
        Users: 400
   Unanswered: 15 (0.003)
   #+end_example
   - users is 200 rep or more
   - the number beside unanswered is a float in [0, 1]
     - 0 :: all questions are answered
     - 1 :: no questions are answered

*** Default Keymap

 - n :: next question (move point down)
 - p :: previous question
 - RET :: enter question ([[*Question%20Detail%20Mode:%20%3Dstack-question-detail-mode%3D][Question Detail Mode]])
 - s :: star a question
 - A :: ask question ([[*Ask%20Mode:%20%3Dstack-ask-mode%3D][Ask Mode]])
 - q :: go back to [[*Network%20Mode:%20%3Dstack-network-mode%3D][Network Mode]]
 - m :: switch to meta
** Question Detail Mode: =stack-question-detail-mode=

Outline-mode-like question voting, comment voting/flagging

This mode is buffer-read-only.

The question and each answer are top-level nodes.

*** Default Keymap

- = :: upvote question/answer
- - :: downvote
- s :: star
- C-u s :: save offline as an =org= node.  (The archive file is kept
           in .emacs.d)
** Comment Mode: =stack-comment-mode=

Minor mode for use atop markdown-mode.

Valid for Questions and Answers; just a small window that would open
up below in comment-mode.  Should support mentions.

*** Default Keymap

- C-c C-c :: Commit comment.
- C-c C-k :: Cancel comment.
- TAB :: Expand username, if possible (must be after =@=)
** Ask Mode: =stack-ask-mode=

A minor mode atop =markdown-mode=, adding support for tagging.

Ask a question.
** Inbox Mode: =stack-inbox-mode=
yeah.  View notifications and stuff.