
Filename: DEVELOPER.txt
Updated:  1200 A.D.


This is just a collection of notes, FAQs, and random ideas related
particularly to Cream development.


Cream Questions and Notes {{{1

o Where are Cream's path variables set?

    In vimrc. All of them.

o Are environmental variables related to Cream's global variables?

    No. Environmental variables are effectively external to Cream's
    inner workings.

o How do the global variables set in cream-conf.vim work?

    Cream establishes a multitude of variables, a few of which are
    global (in the form g:CREAM_*, all caps) and retained between
    editing sessions. cream-conf is simply read after these retained
    varibles have been established so that they take precedence.

o Can there be user-defined modules? (like filetypes)

    Possibly, although we would prefer that quality constructs simply
    become part of the project! (How'd you like to be the maintainer?
    ;) Otherwise, why not just place them into cream-user.vim or at
    least source them from there?

o Restrictions encountered in abstracting module loading and
  dependency structure:
  * "the big three" settings are so important they are set first, in
    creamrc. Example: &shellslash must precede menus. (vimrc)
  * Vim's own gui settings file is unused (gvimrc)
  * developer and version variables precede everything (cream)
  * most modules depend on the library (lib)
  * syntax highlighting must load afer menus (colors)
  * spell check is dependent on syntax highlighting (colors)
  * menus must be loaded prior to syntax highlighting (menus)
  * mappings are loaded independently of functions (keys)
  * autocommands are loaded independently of functions (autocmd)
  * GUI-only features are set appart from remainder (gui)

o What about Alt+letter mappings for menus/filetype mappings?

    As an English speaker, I had never realized that other >26
    character languages use the Alt+letter key to enter digraphs.
    Early on I just assumed that Alt+letter was available for any
    mapping I wanted, but I now think these should be reserved for
    internationalization. Unfortunately, it is also custom to use
    menus in this regard and we have few other simple combinations
    available to map filetype specific functionality.

    One very hopeful possibility is that Vim can read multiple
    repetitions of key combinations. While combinations like
    <M-Q><M-V> are doable, I am inclined to start mapping doubles of
    the same key, such as <M-Q><M-Q>. The downsides are that there is
    hesitation upon entering the diagraph as Vim waits to see if the
    user is going to place another keystroke. But we have recently
    reduced timeout length to 500ms from the default 1000ms and this
    seems tolerable. The biggest question in this scheme is usability.
    Can the average user understand? Are international users satisfied
    with this? Could we make it even more complex with triple or even
    quadruple repititions?

o What's the difference between Settings and Preferences?

    Settings are options whose states are varied depending on the
    particular file being edited. Preferences are option states that
    are particular to a user's habits and editing style.

    The distinction is in rare cases unintuitive. For one person,
    using &expandtab seems to be a preference, while another can see
    its usefulness depending on the task. For example, if you're a C
    coder all day and your company's policy is to use spaces, you
    might never have reason to use tabs. But you may also be a system
    administrator or be participating in a complex project with many
    file types where the language determines the coding style. So the
    overlap could be a problem.

    That said, we believe it makes sense to maintain a root level
    Settings menu which contains a Preferences menu. This provides
    quick access (Alt+S) to all settings, separates personal prefernce
    stuff into a sub-menu and yet still collects them both into
    a single place that one could easily browse through to control the
    editor's behavior.


Cream Architecture {{{1

We're still trying to work this out. Below is an old roadmap, which
may change tomorrow. ;)

Core
----
Interdependent set of scripts that create the main architecture.
Nothing able to be removed.

vimrc and gvimrc
o We start Cream by specifying our creamrc with the "-u" switch and
  "-U NONE" tag to avoid any possible conflicting statements in Vim or
  user vimrc or gvimrc.

creamrc
o Cream's vimrc. This enables Vim to be run without using any Cream
  files.
o Path initializer
o Starts cream.vim.

cream.vim
o Essentially main().
o Loads all other scripts and modules.
o Loads cream-conf.vim first so an abort of the remaining load is
  possible if the user has set behavior to Vim or Vi "mode".
o Loads cream-user.vim last.

cream-conf.vim
o User customizations that "configure" the remaining load. Dynamic
  load routines (developer menu path) must be configured here since it
  will have already been loaded by the time cream-user gets loaded.

cream-lib.vim
o Project-wide functions available to all scripts.

cream-settings.vim
o General settings environment.

(others)


Modules
-------
Scripts dependent on core functions, yet not depended on by the core.
These are just logical groupings of functions to keep the source
maintainable. Includes:

o Misc.: statusline, bookmarks, etc., etc., etc.
o Colors
o Filetypes
o Spell Check

and most other functions we couldn't live without, but which might be
able to be removed without damaging the remainder of the project.


Add-ons
-------
Optional extensions that aren't really critical to the project. Each
has a singular function that is made available to the user through a
menu and permitted to be mapped to a user-defined key.


cream-playpen.vim
  * Experimental and testing stuff loaded penultimately.

cream-user.vim
  * User customized mappings or abbreviations loaded last.


Cream Script Preferences and Code Style Guide {{{1

Functional
----------

* Don't ever use <Esc>. It does different things depending on whether
  insertmode is on or off.

* Always create insertmode mappings for those who use insertmode.

* Avoid loose script commands. Instead, create functions that do
  specific tasks when called.

* Try to have mode passed as an argument to main functions so calling
  mappings, scripts or menus are forced to consider mode.

* Always scope functions and variables when not intended to be global.

* Always write script with &fileformat=unix. &fileformat=dos won't
  work on unix.

* Use register "x as a register local to a function. NEVER use "@ as
  it is the global OS/Cream clipboard.


Style
-----

* Never use Vim's abbreviated forms for commands or options. Always
  use the full name since code readability is paramount! Use

    :%substitute  over  :%s
    :function     over  :fun
    :execute      over  :exe
    :edit         over  :e
    :normal       over  :norm

  and so forth. WE WRITE CODE TO READ, not for entering quickly at
  the command line.

* Always use spaces around operators and concatenation symbols.

* Never use spaces between function names and enclosing parenthesis.

* Don't glob normal commands on one line. Separate them into readable
  chunks.

* Never use the "l:" scope indicator within functions. It's redundant,
  redundant, and repeats information repetatively.


The Evils of <C-L> and <Esc> Keys {{{1
  (or "Using Normal Mode with '&insertmode'")


Statement of the Problem:
---------------------------

* Three keystrokes/combinations exist from which to exit insert mode
  to normal mode:
  - <C-l>
  - <C-o>
  - <C-\><C-n>
* <C-l> can only be used with insertmode on.
* <C-o> and <C-\><C-n> work with insertmode either on or off.
* Both <C-l> and <C-\><C-n> destroy position from an insertmode
  mapping and are unable to accurately position within normal mode
  between a line's first two columns.
* <C-o> does *not* destroy position from an insertmode mapping, but is
  unable to accurately position within normal mode betweeen a line's
  *last* two columns.
* Returning from normal mode via normal i or normal a solves none of
  the above problems. The error in return position is only translated
  to the opposite end of the line. (But nice try though.)


Excerpt from a Vim List Discussion:
-----------------------------------

  To: Benji Fisher
  Cc: Steve Hall, vim@vim.org
  At: 2003-01-14, 6:38pm
  Re: Re: imap and col()

  <C-o> properly returns to the last position, over the invisible
  return character(s), when at col('$'). This is something that
  <C-\><C-n> or <C-l> do not do at any column except column 1,
  effectively destroying the position. (You are faced with the dilema:
  add 1 to the return position everywhere and never be able to
  re-position at 1, or don't add to the return and never re-position
  correctly at 2. Throw in distracting variations of returns via
  normal i or a for good measure.) I maintain that there is no way,
  from an insertmode mapping beginning with either, to know whether
  the mapping began from column 1 or 2.

  Once dropped into normal mode, <C-o> has a similar problem of
  position loss between two col positions, even though the return is
  somehow corrected. I've found it more manageable here than at line
  front, too, since at column 1 or 2 inserts occur frequently and tab
  chars can shift an insert 8 space beyond where expected. However, it
  is quite rare to use a function to insert text one column from line
  end, so it is less noticeable. (Although still an error/bug.)


Discussion of Obtaining Insertmode from Within a Function
---------------------------------------------------------

* When inside a function, Vim is automatically in normal mode. This
  makes some sense--you have to get to the command line to call it.
  But it means you cannot check for mode within a function because you
  will always get "n" for normal. (General script does not behave this
  way, but of course lacks the ability to be mapped or called from
  other script. So we'll disregard "non-functionalized" code for this
  discussion although a portion of the same principles still apply.)

* While within a function, you can change modes using the syntax:

    normal i

  or any of the other many variations. This essentially is the same as
  entering the "i" command from normal mode. (You must use the execute
  format to run a keystroke in combination with Ctrl, Alt, Shift or
  Function keys, such as

    execute "normal \<C-g>"

  and similar.) Once in this new mode, Vim remains there even after
  the function terminates.

* The last mode set within a function remains after it returns. (This
  can be quite dangerous if you like to append normal mode commands
  following a mapping, as we'll explain.)

* To execute a function and then return to insert mode, default Vim
  uses a mapping "<C-o>" such as

    <C-o>:call MyFunction()<CR>

  which is understood to return directly to insertmode after one
  command. *HOWEVER*...


And now the trouble begins...

* Vim provides a mapping "<C-l>" which implies to leave insert mode
  until an "<Esc>" is pressed. However there are some fundamental
  flaws with this command which must be side-stepped.

  o <C-l> must be forced to return to insert mode, via "normal i",
    ":startinsert", "execute 'normal <C-[>'" or the like. The script
    writer must decide how this happens.

  o <C-l> ruins position. To see this, do <C-l><Esc> several times.
    Notice your cursor move backwards one space each time?

    In a more sophisticated example, take the following function and
    mappings:

        function! MyFunction()
            " insert "Cow"
            normal iCow
            " back up
            normal hh
            " scroll screen up one line
            execute "normal \<C-e>"
            " move cursor back down one
            normal gj
        endfunction

        nmap <F12>           :call MyFunction()<CR>
        imap <F12>      <C-l>:call MyFunction()<CR><Esc>

    Place your cursor in the first line below, over the 1 in normal
    mode and press <F12> a few times...

        "-------- Test area ----------
        "23456789012345678901234567890
        "23456789012345678901234567890
        "23456789012345678901234567890
        "23456789012345678901234567890
        "-------- Test area ----------

    Then try it with the cursor between 0 and 1 from insert mode.
    Notice the two are different?

    Now comment out the above two mappings and try these two instead,
    performing the same tests above:

        nmap <F12>      :call MyFunction()<CR>
        imap <F12> <C-o>:call MyFunction()<CR>

    Now both positionings are equal!

    Cream calls all functions using this second method because of the
    erratic positioning behavior of <C-l>. (In only about three
    controled cases do we deviate.)

  o <Esc> terminates in an unpredictable mode. With insertmode on, it
    drops to insert mode, but with insertmode off, <Esc> drops to
    normal mode!

* Matters are further complicated in situations where a mapping calls
  a function and then follows with further keys such as:

     imap <F12> <C-l>:call MyFunction()<CR><Esc><C-e>

  With insertmode on, this mapping correctly calls the function and
  then uses the <Esc> to return normal mode to allow the final <C-e>
  to line scroll once. However if insertmode is off, two errors are
  created. First, <C-l> produces a form feed () character, and
  secondly, <C-e> in Cream toggles Auto Wrap.

In summary, use of the <C-l> and <Esc> keys to manipulate normal mode
is unhelpful except in very rare situations where the script writer is
highly confident that their many unpredictable behaviors are being
properly handled.

Vim Thoughts {{{1

Vim is like a racing car. It provides dashboard controls for the
ignition, fuel pump, brake bias, starter, fuel mixture, suspension
settings, communications, etc, but doesn't have a radio, adjustable
seats, air conditioning, defrost, or anything else you might want
driving to work.

Cream, on the other hand, has a great sound system, can haul cargo and
carry 7 passengers. It also lets you under the hood to add high
performance if want--after all, it's your ticket if it's not street
legal.


1}}}
 vim:foldmethod=marker
