forked from mbert/elvis
-
Notifications
You must be signed in to change notification settings - Fork 0
/
display.c
290 lines (257 loc) · 7.12 KB
/
display.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
/* display.c */
/* Copyright 1995 by Steve Kirkendall */
#include "elvis.h"
#ifdef FEATURE_RCSID
char id_display[] = "$Id: display.c,v 2.23 2003/10/17 17:41:23 steve Exp $";
#endif
/* This is a list of all known display modes. The last mode is the default. */
DISPMODE *allmodes[] =
{
#ifdef DISPLAY_HEX
&dmhex,
#endif
#ifdef DISPLAY_HTML
&dmhtml,
#endif
#ifdef DISPLAY_MAN
&dmman,
#endif
#ifdef DISPLAY_TEX
&dmtex,
#endif
#ifdef DISPLAY_SYNTAX
&dmsyntax,
#endif
&dmnormal
};
/* List the available modes */
void displist(win)
WINDOW win;
{
int i;
char text[100];
for (i = 0; i < QTY(allmodes); i++)
{
sprintf(text, " %c%-6s %s\n",
win->md == allmodes[i] ? '*' : ' ',
allmodes[i]->name,
allmodes[i]->desc);
drawextext(win, toCHAR(text), (int)strlen(text));
}
}
/* Set the edit mode of a given window. If the name of the new mode is NULL,
* then the default display mode is used. If the name doesn't match any known
* mode, then an error message is issued and dispset() returns ElvFalse;
* normally it returns ElvTrue.
*/
ELVBOOL dispset(win, newmode)
WINDOW win; /* window whose edit mode is to be changed */
char *newmode; /* name of the new display mode */
{
int i, len;
/* if no name given, use the default mode */
if (!newmode || !*newmode)
{
i = QTY(allmodes) - 1;
newmode = allmodes[i]->name;
len = strlen(newmode);
}
else /* find the requested mode */
{
for (len = 0; newmode[len] && newmode[len] != ' '; len++)
{
}
for (i = 0; i < QTY(allmodes) && strncmp(allmodes[i]->name, newmode, len); i++)
{
}
if (i >= QTY(allmodes))
{
msg(MSG_ERROR, "[s]bad display mode $1", newmode);
return ElvFalse;
}
}
/* if previous mode, then terminate it */
if (win->md)
{
#ifdef FEATURE_AUTOCMD
(void)auperform(win, ElvFalse, NULL, AU_DISPLAYLEAVE, o_display(win));
#endif
(*win->md->term)(win->mi);
if (optflags(o_display(win)) & OPT_FREE)
{
safefree(o_display(win));
optflags(o_display(win)) &= ~OPT_FREE;
}
}
/* store the display mode */
win->md = allmodes[i];
o_display(win) = CHARdup(toCHAR(newmode));
optflags(o_display(win)) |= OPT_FREE;
win->mi = allmodes[i]->init(win);
#ifdef FEATURE_AUTOCMD
(void)auperform(win, ElvFalse, NULL, AU_DISPLAYENTER, o_display(win));
#endif
return ElvTrue;
}
/* This function is called twice: once before "elvis.ini" is interpreted, and
* again afterward. This function makes EVERY display mode's global options
* available via ":set" so they can be initialized to user-defined values.
*/
void dispinit(before)
ELVBOOL before; /* ElvTrue before "elvis.ini", and ElvFalse after */
{
int i;
/* for each display mode... */
for (i = 0; i < QTY(allmodes); i++)
{
/* if the mode has global options... */
if (allmodes[i]->nglobopts > 0)
{
/* either add its options, or delete them */
if (before)
{
/* allow the mode to initialize its options */
(void)(*allmodes[i]->init)(NULL);
/* make them accessible to :set */
optinsert(allmodes[i]->name,
allmodes[i]->nglobopts,
allmodes[i]->globoptd,
allmodes[i]->globoptv);
}
else
{
optdelete(allmodes[i]->globoptv);
}
}
}
}
/* This function makes a given mode be the default mode... meaning that its
* options are available to the ":set" command.
*/
void dispoptions(mode, info)
DISPMODE *mode; /* the display mode */
DMINFO *info; /* window-dependent options of this mode */
{
static DMINFO *curinfo;
static OPTVAL *curglob;
/* If the global mode options are changing... */
if (!mode || mode->globoptv != curglob)
{
/* delete the old global options, if any */
if (curglob)
{
optdelete(curglob);
}
/* insert the new global options, if any */
if (mode != NULL && mode->nglobopts > 0)
{
optinsert(mode->name, mode->nglobopts, mode->globoptd, mode->globoptv);
curglob = mode->globoptv;
}
else
{
curglob = NULL;
}
}
/* if the window-dependent mode options are changing... */
if (info != curinfo)
{
/* delete old window-dependent mode options, if any */
if (curinfo)
{
optdelete((OPTVAL *)curinfo);
}
/* insert new window-dependent mode options, if any */
if (mode != NULL && info != NULL && mode->nwinopts > 0)
{
optinsert("windisp", mode->nwinopts, mode->winoptd, (OPTVAL *)info);
curinfo = info;
}
else
{
curinfo = NULL;
}
}
}
/* This function calls the "move" function for a mode. If the state stack
* of the given window indicates that we're editing the window's main buffer,
* then the window's mode is used; otherwise, dmnormal is always used.
* If in the original visual command state, then the move function will be
* called for "cmd" behavior.
*/
MARK dispmove(win, linedelta, wantcol)
WINDOW win; /* the window whose mode to use */
long linedelta; /* line movement */
long wantcol; /* desired column number */
{
ELVBOOL cmd;
/* use "cmd" behavior if in vi command state */
cmd = viiscmd(win);
/* call the right function */
if (win->state->acton)
{
/* editing a history buffer - use dmnormal */
return (*dmnormal.move)(win, win->state->cursor, linedelta, wantcol, cmd);
}
else
{
/* editing window's main buffer - use window's mode */
return (*win->md->move)(win, win->state->cursor, linedelta, wantcol, cmd);
}
}
/* This function calls the "mark2col" function for a mode. If the state stack
* of the given window indicates that we're editing the window's main buffer,
* then the window's mode is used; otherwise, dmnormal is always used.
* If in the original visual command state, then the move function will be
* called for "cmd" behavior.
*/
long dispmark2col(win)
WINDOW win; /* window whose mode to use */
{
ELVBOOL cmd = ElvFalse ;
/* use "cmd" behavior if in vi command state */
if (!win->state->pop)
{
cmd = ElvTrue;
}
/* call the right function */
if (win->state->acton)
{
/* editing a history buffer - use dmnormal */
return (*dmnormal.mark2col)(win, win->state->cursor, cmd);
}
else
{
/* editing window's main buffer - use window's mode */
return (*win->md->mark2col)(win, win->state->cursor, cmd);
}
}
/* This function implements autoindent. Given the MARK of a newly created
* line, insert a copy of the indentation from another line. The line whose
* indentation is to be copied is specified as a line delta. Usually, this
* will be -1 so the new line has the same indentation as a previous line.
* The <Shift-O> command uses a linedelta of 1 so the new line will have the
* same indentation as the following line.
*/
void dispindent(w, line, linedelta)
WINDOW w; /* windows whose options are used */
MARK line; /* new line to adjust */
long linedelta; /* -1 to copy from previous line, etc. */
{
/* autoindent only works if supported and turned on, and even then
* only if we're editing the window's main edit buffer.
*/
if (!w->md->indent
|| !o_autoindent(markbuffer(w->cursor))
|| markbuffer(w->cursor) != markbuffer(line))
{
return;
}
/* call the mode's indent function */
(*w->md->indent)(w, line, linedelta);
/* if necessary, extend the edit region to include the cursor's
* new position.
*/
if (markoffset(w->state->cursor) > markoffset(w->state->bottom))
marksetoffset(w->state->bottom, markoffset(w->state->cursor));
}