blob: aa8509d09ed00dfbbabd2281dc31aeb9543d93e6 [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// MorgenGrauen MUDlib
2//
3// util/ex.c -- ex compatible editor
4//
5// $Id: ex.c 9142 2015-02-04 22:17:29Z Zesstra $
6
7#pragma strong_types
8#pragma save_types
MG Mud User88f12472016-06-24 23:31:02 +02009#pragma range_check
10#pragma no_clone
11
12inherit "/std/util/input";
13
14private nosave mapping ctrl = ([]);
15private nosave mixed buf;
16
17#include <sys_debug.h>
18#undef ARGS
19#include <wizlevels.h>
20#include <player.h>
21
22#define MODE 0
23# define CMD 0
24# define INP 1
25#define TEXT 1
26#define LINE 2
27#define FUNC 3
28#define ARGS 4
29#define FLAG 5
30# define NUM 1
31#define CHG 6
32
33#define YANK "@YANK"
34
35int evaluate(string in);
36
37varargs int error(string msg, string arg)
38{
39 if(stringp(arg)) write(arg+": "+msg+"\n");
40 else write(msg+"\n");
41}
42
43string substitute(string s, string regex, string n, string extra)
44{
45 mixed del; int i;
46 if((i = sizeof(del = regexplode(s, regex))) < 2) return s;
47 if(member(extra, 'g') == -1) i = 1;
48 else i -= 2;
49 while(i>0) {
50 del[i] = n;
51 i -= 2;
52 }
53 return implode(del, "");
54}
55
56// saveText() -- save edited text
57//
58int saveText()
59{
60 string text;
61 text = implode(ctrl[buf][TEXT][1..], "\n")+"\n";
62 error(sprintf("%O, %d Zeilen, %d Zeichen",
63 buf ? buf : "", sizeof(ctrl[buf][TEXT])-1,
64 sizeof(text)));
65 if(ctrl[buf][FUNC]) apply(ctrl[buf][FUNC], ctrl[buf][ARGS], text);
66 ctrl = m_copy_delete(ctrl, buf);
67 ctrl = m_copy_delete(ctrl, buf+"!");
68 buf = 0;
69 return 1;
70}
71
72// cmdPrompt() -- create command prompt
73//
74string cmdPrompt(int mode, mixed text, int line, int maxl)
75{
76 return ":";
77}
78
79// inputPrompt() -- create input prompt
80//
81string inputPrompt()
82{
83 if(ctrl[buf][FLAG] & NUM) return sprintf("[%02d] ", ctrl[buf][LINE]);
84 return "";
85}
86
87string AddNum(string s)
88{
89 string r;
90 r = inputPrompt()+s;
91 ctrl[buf][LINE]++;
92 return r;
93}
94
95void showLines(int from, int to)
96{
97 write(implode(map(ctrl[buf][TEXT][from..to], #'AddNum), "\n")+"\n");
98 ctrl[buf][LINE] = from;
99}
100
101// commandMode() -- handle commands
102//
103int commandMode(string in)
104{
105 int from, to, swap;
106 string cmd;
107
108 if(!in) return 0;
109 if(in[0..1] == "se") {
110 ctrl[buf][FLAG] ^= NUM;
111 return 0;
112 }
113
114 if(sscanf(in, "%d,%d%s", from, to, cmd) != 3)
115 if(sscanf(in, "%d%s", from, cmd) != 2)
116 if(!stringp(in)) return error("Kein Editorkommando", in);
117 else { cmd = in; from = to = ctrl[buf][LINE]; }
118 else to = from;
119
120 if(from < 0) from = sizeof(ctrl[buf][TEXT])-1+from;
121 if(to < 1) to = sizeof(ctrl[buf][TEXT])-1+to;
122 if(to && to < from) return error("Erste Adresse groesser als die Zweite");
123 if(from) ctrl[buf][LINE] = from;
124 if(from > sizeof(ctrl[buf][TEXT])-1 ||
125 to > sizeof(ctrl[buf][TEXT])-1)
126 return error("Nicht so viele Zeilen im Speicher");
127 if(!to) to = from;
128 switch(cmd[0])
129 {
130 case 'h':
131 write("ex: Kommandohilfe\n\n"
132 "Alle Kommandos funktionieren nach folgendem Prinzip:\n"
133 "Adresse Kommando Argumente\n"
134 "Adressen werden gebildet durch: ZeileVon,ZeileBis\n"
135 "(ZeileBis kann weggelassen werden, samt Komma)\n"
136 "Kommandos:\n"
137 " q,x -- Editor verlassen\n"
138 " r -- Datei einfuegen\n"
139 " r<datei>\n"
140 " a -- Text hinter der aktuellen Zeile einfuegen\n"
141 " i -- Text vor der aktuellen Zeile einfuegen\n"
142 " d -- Zeilen loeschen\n"
143 " y -- Zeilen zwischenspeichern\n"
144 " pu -- Zwischengespeicherte Zeilen einfuegen\n"
145 " s -- Substitution von Text in Zeilen\n"
146 " s/AlterText/NeuerText/\n"
147 " p,l -- Zeilen anzeigen\n"
148 " z -- Eine Seite anzeigen\n");
149 break;
150 case 'q':
151 if(ctrl[buf][CHG])
152 if(!(sizeof(cmd) > 1 && cmd[1]=='!'))
153 return error("Datei wurde geaendert! Abbrechen mit q!");
154 else ctrl[buf] = ctrl[buf+"!"];
155 case 'x':
156 if(saveText()) return 1;
157 case 'r':
158 if(!IS_WIZARD(this_player()))
159 return error("Kommando gesperrt", cmd[0..0]);
160 if(file_size(cmd[1..]) < 0)
161 return error("Datei nicht gefunden", "\""+cmd[1..]+"\"");
162 ctrl[buf][TEXT] = ctrl[buf][TEXT][0..from]
163 + explode(read_file(cmd[1..]), "\n")
164 + ctrl[buf][TEXT][(from == to ? to+1 : to)..];
165 ctrl[buf][CHG] = 1;
166 break;
167 case 'a':
168 ctrl[buf][MODE] = INP;
169 write("Texteingabe: (. beendet zum Kommandomodus, ** beendet ganz)\n");
170 input(#'inputPrompt, 0, #'evaluate);
171 ctrl[buf][CHG] = 1;
172 return 1;
173 case 'i':
174 ctrl[buf][MODE] = INP;
175 ctrl[buf][LINE]--;
176 write("Texteingabe: (. beendet zum Kommandomodus, ** beendet ganz)\n");
177 input(#'inputPrompt, 0, #'evaluate);
178 ctrl[buf][CHG] = 1;
179 return 1;
180 case 'd':
181 ctrl[buf][TEXT][from..to] = ({});
182 ctrl[buf][CHG] = 1;
183 break;
184 case 'y':
185 ctrl[YANK] = ctrl[buf][TEXT][from..to];
186 if(to - from) error(to-from+1+" Zeilen gespeichert");
187 break;
188 case 's':
189 {
190 mixed reg, new, extra, scmd;
191 if(sizeof(scmd = old_explode(cmd[1..], cmd[1..1])) < 2)
192 return error("Substitution fehlgeschlagen");
193 reg = scmd[0]; new = scmd[1];
194 if(sizeof(scmd) > 2) extra = scmd[2];
195 else extra = "";
196 ctrl[buf][TEXT][from..to] = map(ctrl[buf][TEXT][from..to],
197 #'substitute,
198 reg, new, extra);
199 showLines(from, to);
200 ctrl[buf][CHG] = 1;
201 break;
202 }
203 case 'z':
204 showLines(ctrl[buf][LINE],
205 ctrl[buf][LINE]+this_player()->QueryProp(P_SCREENSIZE));
206 ctrl[buf][LINE] += this_player()->QueryProp(P_SCREENSIZE);
207 break;
208 case 'p':
209 if(sizeof(cmd) > 1 && cmd[1] == 'u')
210 {
211 if(!pointerp(ctrl[YANK])) return error("Keine Zeilen im Speicher");
212 if(from >= ctrl[buf][LINE]) ctrl[buf][TEXT] += ctrl[YANK];
213 else
214 ctrl[buf][TEXT][0..from] + ctrl[YANK] + ctrl[buf][TEXT][from+1..];
215 ctrl[buf][LINE] += sizeof(ctrl[YANK]);
216 ctrl[YANK] = 0;
217 showLines(ctrl[buf][LINE], ctrl[buf][LINE]);
218 break;
219 }
220 case 'l':
221 default:
222 if(!from)
223 {
224 error("Kein Editorkommando", sprintf("%c", cmd[0]));
225 return 0;
226 }
227 showLines(from, to);
228 }
229 input(#'cmdPrompt, 0, #'evaluate);
230 return 1;
231}
232
233// inputMode() -- handle input mode commands
234//
235int inputMode(string in)
236{
237 switch(in)
238 {
239 case ".":
240 ctrl[buf][MODE] = CMD;
241 ctrl[buf][LINE]--;
242 input(#'cmdPrompt, 0, #'evaluate);
243 break;
244 case "**":
245 return saveText();
246 default:
247 if(!in) /* do nothing now */;
248 if(ctrl[buf][LINE] < sizeof(ctrl[buf][TEXT])-1)
249 ctrl[buf][TEXT] = ctrl[buf][TEXT][0..ctrl[buf][LINE]-1] + ({ in })
250 + ctrl[buf][TEXT][ctrl[buf][LINE]..];
251 else ctrl[buf][TEXT] += ({ in });
252 ctrl[buf][LINE]++;
253 input(#'inputPrompt, 0, #'evaluate);
254 break;
255 }
256 return 1;
257}
258
259// evaluate() -- evaluate input (in) in context (ctrl[buf])
260//
261int evaluate(string in)
262{
263 switch(ctrl[buf][MODE])
264 {
265 case INP: return inputMode(in);
266 case CMD: return commandMode(in);
267 default : return 0;
268 }
269}
270
271void StartEX(string in, mixed c)
272{
273 if(!in || in == "j" || in == "J") ctrl[buf] = c;
274 else if(in && (in != "n" || in != "N"))
275 return 0;
276 ctrl[buf+"!"] = ctrl[buf];
277 input(#'cmdPrompt, 0, #'evaluate);
278}
279
280varargs int ex(mixed text, closure func, mixed fargs, string buffer)
281{
282 int c, l;
283 mixed ct;
284 if(!text) text = "";
285 c = sizeof(text);
286 l = sizeof(text = explode(text, "\n")) - 1;
287 ct = ({ CMD, text, 0, func, fargs, 0, 0});
288 if(!ctrl[buffer]) StartEX(0, ct);
289 else input(sprintf("Es existiert bereits Text! Verwerfen? [j]"),
290 0, #'StartEX, ct);
291 return 1;
292}