Line editor (more text here) In the misty years of yore, when fanfold terminals walked the earth, there lived a strange creature. Oddly crippled and yet oddly powerful, the line editor teemed across the programming landscape in untold numbers; covering the earth as far as the eye could see.
Now it is fallen on hard times. That vast population hunted, hounded, and driven to the brink of extinction. Only a few specimens remain, most in cramped and unembelished cages in the less enlightened kind of zoo, though a few stuffed and mounted examples can be seen in backwater museums. Oh, and there is ed.
Frankenstein-like, we shall resurrect the noble beast!
Commands
Our editor is fairly minimal and will support the following commands
Focus moving commands

&lt;number&gt;[,&lt;number&gt;] -- move the focus to the stated line and if the second argument is given to the state column. Excessive line number gets the last line. Excessive column number gets the end of the line.
,&lt;number&gt; -- move to column number on the current line
e -- move the focus to the end of the file but do not begin a new line.
b -- move the focus to the beginning of the file.

Informational commands

L -- Echo the current context. The five lines centered on the current line are printed. All five lines are indented by one character; the current line is marked with a &quot;&gt;&quot;, the others with a &quot; &quot;. Under these lines another line is printed consisting entirely of spaces except for a &quot;^&quot; in the current column (a total of six lines are printed).
l -- echo the current line
p [[&lt;start&gt;],[&lt;end&gt;]] -- Print the file from starting to ending address. These value default to 1 and 0 (the end of the file).

File altering commands

A [&lt;text&gt;] -- Move to the line beyond the end of the file (that is begin a new line) and (possibly) append text.
&lt;return&gt; (alone) -- Insert a newline. Thus a &lt;return&gt; &lt;return&gt; inserts a newline after the current one.
r &lt;text&gt; -- replaces everything from the focus to the end of the line with text.
i [&lt;text&gt;] -- inserts text followed by by newline at the current focus. Any portion of this line beyond the focus ends up on the next line.
I &lt;text&gt; -- inserts text at the current focus, preserving the rest of the line. Focus remains on this line.
d -- Delete the contents of the current line or if the current line is already empty, remove the line.
j -- join this line to the next

Of this last group the first four end with the focus moving to the next line, while I preserves the focus at the end of the added text. When deleting or joining focus remains at the same line and column number.
The Interpretation of line numbers in commands
Number beginning with '+' or '-' are interpreted as offsets from the current line number. Numbers without a sign are interpreted as absolute line numbers, except that '0' means the last line of the file.
Prompt and interaction
The editor functions as a shell, and the prompt has the form &lt;line&gt;','&lt;column&gt;'&gt;' where line is the line number except that &quot;end&quot; is used when the focus is at the last character of the file.
Each command is accepted only when the user presses newline. And takes affect.
Readline support is allowed but not required.
No feedback is provided except the changing values of  and  in the prompt, unless explicitly stated in the commands description.
Scoring
This is code-golf, so the shortest answer in each language wins.
Special thanks to dmkee for making this in sandbox where I adopted it.
C (gcc), 1288 1212 1188 1171 1146 bytes

#define P printf(
#define A case
#define B break
#define L(i,e,t,f,s)for(o=i;o e;){strcpy(l[o t],l[o f]);c[o t]=c[s o];}
#define R(m,o){return b&lt;1|b&gt;m?m o:b;}
#define N(f)sscanf(f,"%d,%d",&amp;i,&amp;j)||sscanf(f,",%d",&amp;j)
r,i,j,o,z,c[999],*C,x=1,y=1;char a[999],l[999][999],(*L)[999];D(){L(r,&gt;y,,-1,--)r++?strcpy(l[o],l[o-1]+--x),c[o-1]=x,l[o-1][x]=0:0;c[y++]=strlen(l[o]);x=1;}U(){strcat(*L,l[y]);*C=strlen(*L);L(y+1,&lt;r,-1,,++)--r;*l[r]=c[r]=0;}X(b)R(c[y-1],+1)Y(b)R(r,)main(){for(;;){z=i=y;L=l+--z;C=c+z;j=x;!r||y/r&amp;&amp;x&gt;*C?P"end&gt; "):P"%d,%d&gt; ",y,x);scanf("%[^\n]%*c",a)?a[2]*=!!a[1],N(a)?y=Y(i+(i&lt;0|*a=='+')*y),x=X(j+(j&lt;0||strchr(a+1,'+'))*x):0:(*a=D(),scanf("%*c"));switch(*a){A'e':y=r;x=c[r-1]+1;B;A'b':y=1;x=1;B;A'L':for(o=y-4;++o&lt;y+2;)o&lt;0^o&lt;r&amp;&amp;P"%c%s\n",o^z?' ':'&gt;',l[o]);for(o=x+1;--o;)P" ");P"^\n");B;A'l':puts(*L);B;A'p':i=1;j=0;N(a+2);for(o=Y(i)-1;o&lt;Y(j);++o)puts(l[o]);B;A'A':y=r++;strcpy(l[y],a+2);x=c[y]=strlen(a+2);++x;++y;B;A'i':D();--y;x=X(0);A'r':strcpy(*L+x-1,a+2);*C=strlen(*L);x=1;++y&gt;r&amp;&amp;++r;B;A'I':o=strlen(a+2);memmove(*L+x+o-1,*L+x-1,*C-x+1);*C+=o;memcpy(*L+x-1,a+2,o);x+=o;B;A'd':**L?**L=*C=0,x=1:U();y=y&gt;r?r:y;B;A'j':y&lt;r&amp;&amp;U();}}}


Demo

First time trying to do something like this, so there are probably some missed opportunities for making it smaller. (Thanks Jerry Jeremiah for pointing out some)

Here's a (slightly) more readable version:

// often used functions/keywords:
#define P printf(
#define A case
#define B break

// loops for copying rows upwards/downwards are similar -&gt; macro
#define L(i,e,t,f,s)for(o=i;o e;){strcpy(l[o t],l[o f]);c[o t]=c[s o];}

// range check for rows/columns is similar -&gt; macro
#define R(m,o){return b&lt;1|b&gt;m?m o:b;}

// checking for numerical input is needed twice (move and print command):
#define N(f)sscanf(f,"%d,%d",&amp;i,&amp;j)||sscanf(f,",%d",&amp;j)

// room for 999 rows with each 999 cols (not specified, should be enough)
// also declare "current line pointers" (*L for data, *C for line length),
// an input buffer (a) and scratch variables
r,i,j,o,z,c[999],*C,x=1,y=1;char a[999],l[999][999],(*L)[999];

// move rows down from current cursor position
D()
{
    L(r,&gt;y,,-1,--)
    r++?strcpy(l[o],l[o-1]+--x),c[o-1]=x,l[o-1][x]=0:0;
    c[y++]=strlen(l[o]);
    x=1;
}

// move rows up, appending uppermost to current line
U()
{
    strcat(*L,l[y]);
    *C=strlen(*L);
    L(y+1,&lt;r,-1,,++)
    --r;
    *l[r]=c[r]=0;
}

// normalize positions, treat 0 as max
X(b)R(c[y-1],+1)
Y(b)R(r,)

main()
{
    for(;;)
    {
        // initialize z as current line index, the current line pointers,
        // i and j for default values of positioning
        z=i=y;L=l+--z;C=c+z;j=x;

        // prompt:
        !r||y/r&amp;&amp;x&gt;*C?P"end&gt; "):P"%d,%d&gt; ",y,x);

        // read a line of input (using scanf so we don't need an include)
        scanf("%[^\n]%*c",a)?

        // no command arguments -&gt; make check easier:
        a[2]*=!!a[1],

        // numerical input -&gt; have move command:
        // calculate new coordinates, checking for "relative"
        N(a)?y=Y(i+(i&lt;0|*a=='+')*y),x=X(j+(j&lt;0||strchr(a+1,'+'))*x):0:

        // check for empty input, read single newline and perform &lt;return&gt; command:
        (*a=D(),scanf("%*c"));

        switch(*a)
        {
            A'e':y=r;x=c[r-1]+1;B;
            A'b':y=1;x=1;B;
            A'L':for(o=y-4;++o&lt;y+2;)o&lt;0^o&lt;r&amp;&amp;P"%c%s\n",o^z?' ':'&gt;',l[o]);for(o=x+1;--o;)P" ");P"^\n");B;
            A'l':puts(*L);B;
            A'p':i=1;j=0;N(a+2);for(o=Y(i)-1;o&lt;Y(j);++o)puts(l[o]);B;
            A'A':y=r++;strcpy(l[y],a+2);x=c[y]=strlen(a+2);++x;++y;B;
            A'i':D();--y;x=X(0);
            // Commands i and r are very similar -&gt; fall through from i to r
            // after moving rows down and setting position at end of line:
            A'r':strcpy(*L+x-1,a+2);*C=strlen(*L);x=1;++y&gt;r&amp;&amp;++r;B;
            A'I':o=strlen(a+2);memmove(*L+x+o-1,*L+x-1,*C-x+1);*C+=o;memcpy(*L+x-1,a+2,o);x+=o;B;
            A'd':**L?**L=*C=0,x=1:U();y=y&gt;r?r:y;B;
            A'j':y&lt;r&amp;&amp;U();
        }
    }
}




This challenge leaves quite a lot of corner cases to explore -- I guess I fixed all bugs by now, but if somebody finds one more, please comment. Regarding the revisions, I removed byte counts for earlier versions that contained subtle bugs.