HelpBrowser: path box becomes a more conventional search box
[supercollider.git] / SCClassLibrary / Common / Collections / String.sc
blob5d2358845f16e0353b8ec6650f084e67103a705d
1 String[char] : RawArray {
2         classvar <>unixCmdActions;
4         *initClass {
5                 unixCmdActions = IdentityDictionary.new;
6         }
8         *doUnixCmdAction {
9                 arg res, pid;
10                 unixCmdActions[pid].value(res, pid);
11                 unixCmdActions.removeAt(pid);
12         }
14         prUnixCmd {
15                 arg postOutput = true;
16                 _String_POpen
17                 ^this.primitiveFailed
18         }
20         // runs a unix command and sends stdout to the post window
21         unixCmd {
22                 arg action, postOutput = true;
23                 var pid;
24                 pid = this.prUnixCmd(postOutput);
25                 if(action.notNil) {
26                         unixCmdActions.put(pid, action);
27                 };
28                 ^pid;
29         }
31         // Like unixCmd but gets the result into a string
32         unixCmdGetStdOut {
33                 var pipe, lines, line;
35                 pipe = Pipe.new(this, "r");
36                 lines = "";
37                 line = pipe.getLine;
38                 while({line.notNil}, {lines = lines ++ line ++ "\n"; line = pipe.getLine; });
39                 pipe.close;
41                 ^lines;
42         }
44         asSymbol {
45                 _StringAsSymbol
46                 ^this.primitiveFailed
47         }
48         asInteger {
49                 _String_AsInteger
50                 ^this.primitiveFailed
51         }
52         asFloat {
53                 _String_AsFloat
54                 ^this.primitiveFailed
55         }
56         ascii {
57                 ^Array.fill(this.size, { |i| this[i].ascii })
58         }
60         stripRTF {
61                 _StripRtf
62                 ^this.primitiveFailed
63         }
65         stripHTML {
66                 _StripHtml
67                 ^this.primitiveFailed
68         }
70         getSCDir {
71                 _String_GetResourceDirPath
72                 ^this.primitiveFailed
73         }
75         *scDir {
76                 ^"".getSCDir
77         }
79         compare { arg aString, ignoreCase=false; _StringCompare }
80         < { arg aString; ^this.compare(aString, true) < 0 }
81         > { arg aString; ^this.compare(aString, true) > 0 }
82         <= { arg aString; ^this.compare(aString, true) <= 0 }
83         >= { arg aString; ^this.compare(aString, true) >= 0 }
84         == { arg aString; ^this.compare(aString, true) == 0 }
85         != { arg aString; ^this.compare(aString, true) != 0 }
86         hash { _StringHash }
88         // no sense doing collect as per superclass collection
89         performBinaryOpOnSimpleNumber { arg aSelector, aNumber;
90                 ^aNumber.asString.perform(aSelector, this);
91         }
92         performBinaryOpOnComplex { arg aSelector, aComplex;
93                 ^aComplex.asString.perform(aSelector, this);
94         }
96         isString { ^true }
97         asString { ^this }
98         asCompileString { _String_AsCompileString; }
99         species { ^String }
101         postln { _PostLine }
102         post { _PostString }
103         postcln { "// ".post; this.postln; }
104         postc { "// ".post; this.post; }
106         postf { arg ... items;  ^this.prFormat( items.collect(_.asString) ).post }
107         format { arg ... items; ^this.prFormat( items.collect(_.asString) ) }
108         prFormat { arg items; _String_Format ^this.primitiveFailed }
109         matchRegexp { arg string, start = 0, end; _String_Regexp ^this.primitiveFailed }
111         fformat { arg ... args;
112                 var str, resArgs, val, func;
113                 var suffixes, sig = false;
115                 this.do { |char|
116                         if(sig) {
117                                 val = args.removeAt(0);
118                                 func = Post.formats[char];
119                                 if(func.isNil) {
120                                         resArgs = resArgs.add(val);
121                                         str = str ++ char
122                                 } {
123                                         resArgs = resArgs.add(func.value(val))
124                                 };
125                                 sig = false;
126                         } {
127                                 str = str ++ char
128                         };
129                         if(char == $%) { sig = true };
130                 };
131                 ^str.format(*resArgs)
132         }
134         die { arg ... culprits;
135                 if(culprits.notEmpty,{
136                         ("\n\nFATAL ERROR: ").postln;
137                         culprits.do({ arg c; if(c.isString,{c.postln},{c.dump}) });
138                 });
139                 Error(this).throw;
140         }
141         error { "ERROR:\n".post; this.postln; }
142         warn { "WARNING:\n".post; this.postln }
143         inform { ^this.postln }
144         ++ { arg anObject; ^this prCat: anObject.asString; }
145         + { arg anObject; ^this prCat: " " prCat: anObject.asString; }
146         catArgs { arg ... items; ^this.catList(items) }
147         scatArgs { arg ... items; ^this.scatList(items) }
148         ccatArgs { arg ... items; ^this.ccatList(items) }
149         catList { arg list;
150                 // concatenate this with a list as a string
151                 var string = this.copy;
152                 list.do({ arg item, i;
153                         string = string ++ item;
154                 });
155                 ^string
156         }
157         scatList { arg list;
158                 var string = this.copy;
159                 list.do({ arg item, i;
160                         string = string prCat: " " ++ item;
161                 });
162                 ^string
163         }
164         ccatList { arg list;
165                 var string = this.copy;
166                 list.do({ arg item, i;
167                         string = string prCat: ", " ++ item;
168                 });
169                 ^string
170         }
171         split { arg separator=$/;
172                 var word="";
173                 var array=[];
174                 separator=separator.ascii;
176                 this.do({arg let,i;
177                         if(let.ascii != separator ,{
178                                 word=word++let;
179                         },{
180                                 array=array.add(word);
181                                 word="";
182                         });
183                 });
184                 ^array.add(word);
185         }
187         containsStringAt { arg index, string;
188                 ^compare( this[index..index + string.size-1], string, false) == 0
189         }
191         icontainsStringAt { arg index, string;
192                 ^compare( this[index..index + string.size-1], string, true) == 0
193         }
196         contains { arg string, offset = 0;
197                 ^this.find(string, false, offset).notNil
198         }
199         containsi { arg string, offset = 0;
200                 ^this.find(string, true, offset).notNil
201         }
203         findRegexp { arg regexp, offset = 0;
204        _String_FindRegexp
205        ^this.primitiveFailed
206         }
208         findAllRegexp { arg string, offset = 0;
209                 var indices = [], i=[];
210                 while {
211                         i = this.findRegexp(string, offset);
212                         i.notNil and: {i.size != 0}
213                 }{
214                         indices = indices.add(i);
215                         offset = i[0][0] + 1;
216                 }
217                 ^indices
218         }
220         find { arg string, ignoreCase = false, offset = 0;
221                 _String_Find
222                 ^this.primitiveFailed
223         }
224         findBackwards { arg string, ignoreCase = false, offset = 0x7FFFFFFE;
225                 _String_FindBackwards
226                 ^this.primitiveFailed
227         }
228         endsWith { arg string;
229                 ^this.contains(string, this.size - string.size)
230         }
231         beginsWith { arg string;
232                 ^this.containsStringAt(0, string)
233         }
234         findAll { arg string, ignoreCase = false, offset=0;
235                 var indices, i=0;
236                 while {
237                         i = this.find(string, ignoreCase, offset);
238                         i.notNil
239                 }{
240                         indices = indices.add(i);
241                         offset = i + 1;
242                 }
243                 ^indices
244         }
245         replace { arg find, replace;
246                 ^super.replace(find, replace).join
247         }
250         escapeChar { arg charToEscape; // $"
251                 ^this.class.streamContents({ arg st;
252                         this.do({ arg char;
253                                 if(char == charToEscape,{
254                                         st << $\\
255                                 });
256                                 st << char;
257                         })
258                 })
259         }
260         quote {
261                 ^"\"" ++ this ++ "\""
262         }
263         tr { arg from,to;
264                 ^this.collect({ arg char;
265                         if(char == from,{to},{char})
266                 })
267         }
269         insert { arg index, string;
270                 ^this.keep(index) ++ string ++ this.drop(index)
271         }
273         wrapExtend { arg size;
274                 ^this.dup(size div: this.size).join
275         }
277         zeroPad {
278                 ^" " ++ this ++ " "
279         }
281         padLeft { arg size, string = " ";
282                 ^string.wrapExtend(max(0, size - this.size)) ++ this
283         }
285         padRight { arg size, string = " ";
286                 ^this ++ string.wrapExtend(max(0, size - this.size))
287         }
289         underlined { arg char = $-;
290                 ^this ++ "\n" ++ String.fill(this.size, char)
291         }
293         scramble {
294                 ^this.as(Array).scramble.as(String)
295         }
297         rotate { arg n = 1;
298                 ^this.as(Array).rotate(n).as(String)
299         }
301         compile { ^thisProcess.interpreter.compile(this); }
302         interpret { ^thisProcess.interpreter.interpret(this); }
303         interpretPrint { ^thisProcess.interpreter.interpretPrint(this); }
305         *readNew { arg file;
306                 ^file.readAllString;
307         }
308         prCat { arg aString; _ArrayCat }
310         printOn { arg stream;
311                 stream.putAll(this);
312         }
313         storeOn { arg stream;
314                 stream.putAll(this.asCompileString);
315         }
317         inspectorClass { ^StringInspector }
319         /// unix
321         standardizePath {
322                 _String_StandardizePath
323                 ^this.primitiveFailed
324         }
325         withTrailingSlash {
326                 var sep = thisProcess.platform.pathSeparator;
327                 if(this.last != sep, {
328                         ^this ++ sep
329                 },{
330                         ^this
331                 })
332         }
333         withoutTrailingSlash {
334                 var sep = thisProcess.platform.pathSeparator;
335                 if(this.last == sep,{
336                         ^this.copyRange(0, this.size-2)
337                 },{
338                         ^this
339                 })
340         }
342         absolutePath {
343                 var first, sep;
344                 sep = thisProcess.platform.pathSeparator;
345                 first = this[0];
346                 if(first == sep){^this};
347                 if(first == $~){^this.standardizePath};
348                 ^File.getcwd ++ sep ++ this;
349         }
351         pathMatch { _StringPathMatch ^this.primitiveFailed } // glob
352         load {
353                 ^thisProcess.interpreter.executeFile(this);
354         }
355         loadPaths { |warn=true|
356                 var paths = this.pathMatch;
357                 if(warn and:{paths.isEmpty}) { ("no files found for this path:" + this.quote).warn };
358                 ^paths.collect({ arg path;
359                         thisProcess.interpreter.executeFile(path);
360                 });
361         }
362         loadRelative {
363                 var path = thisProcess.nowExecutingPath;
364                 if(path.isNil) { Error("can't load relative to an unsaved file").throw};
365                 if(path.basename == this) { Error("should not load a file from itself").throw };
366                 ^(path.dirname ++ thisProcess.platform.pathSeparator ++ this).loadPaths
367         }
368         resolveRelative {
369                 var path = thisProcess.nowExecutingPath;
370                 if(this[0] == thisProcess.platform.pathSeparator, {^this});
371                 if(path.isNil) { Error("can't resolve relative to an unsaved file").throw};
372                 ^(path.dirname ++ thisProcess.platform.pathSeparator ++ this)
373         }
374         include {
375                 if(Quarks.isInstalled(this).not) {
376                         Quarks.install(this);
377                         "... the class library may have to be recompiled.".postln;
378                         // maybe check later whether there are .sc files included.
379                 }
380         }
381         exclude {
382                 if(Quarks.isInstalled(this)) {
383                         Quarks.uninstall(this);
384                         "... the class library may have to be recompiled.".postln;
385                 }
386         }
387         basename {
388                 _String_Basename;
389                 ^this.primitiveFailed
390         }
391         dirname {
392                 _String_Dirname;
393                 ^this.primitiveFailed
394         }
395         splitext {
396                 this.reverseDo({ arg char, i;
397                         if (char == $\., {
398                                 ^[this.copyFromStart(this.size - 2 - i), this.copyToEnd(this.size - i)]
399                         });
400                 });
401                 ^[this, nil]
402         }
404         // path concatenate
405         +/+ { arg path;
406                 var pathSeparator = thisProcess.platform.pathSeparator;
408                 if (path.respondsTo(\fullPath)) {
409                         ^PathName(this +/+ path.fullPath)
410                 };
412                 if (this.last == pathSeparator or: { path.first == pathSeparator }) {
413                         ^this ++ path
414                 };
416                 ^this ++ pathSeparator ++ path
417         }
419         asRelativePath { |relativeTo|
420                 ^PathName(this).asRelativePath(relativeTo)
421         }
422         asAbsolutePath {
423                         // changed because there is no need to create a separate object
424                         // when String already knows how to make an absolute path
425                 ^this.absolutePath;  // was ^PathName(this).asAbsolutePath
426         }
428         // runs a unix command and returns the result code.
429         systemCmd { _String_System ^this.primitiveFailed }
431         gethostbyname { _GetHostByName ^this.primitiveFailed }
433         // gets value of environment variable
434         getenv {
435                 _String_Getenv
436                 ^this.primitiveFailed
437         }
438         // sets value of environment variable
439         // value may be nil to unset the variable
440         setenv { arg value;
441                 _String_Setenv
442                 ^this.primitiveFailed
443         }
444         unsetenv {
445                 ^this.setenv(nil)
446         }
448         /// code gen
449         codegen_UGenCtorArg { arg stream;
450                 stream << this.asCompileString;
451         }
452         ugenCodeString { arg ugenIndex, isDecl, inputNames=#[], inputStrings=#[];
453                 _UGenCodeString
454                 ^this.primitiveFailed
455         }
457         asSecs { |maxDays = 365| // assume a timeString of ddd:hh:mm:ss.sss. see asTimeString.
458                 var time = 0, sign = 1, str = this;
459                 var limits = [inf, 60, 60, 24, maxDays];
460                 var scaling = [0.001, 1.0, 60.0, 3600.0, 86400.0];
461                 var padding = [3, 2, 2, 2, 3];
463                 if (this.first == $-) {
464                         str = this.drop(1);
465                         sign = -1
466                 };
468                 str.split($:).reverseDo { |num, i|
469                         num = num.padRight(padding[i], "0").asInteger;
470                         if (num > limits[i]) {
471                                 ("asSecs: number greater than allowed:" + this).warn;
472                                 num = limits[i];
473                         };
474                         if (num < 0) {
475                                 ("asSecs: negative numbers within slots not supported:" + this).warn;
476                                 num = 0;
477                         };
478                         time = time + (num * scaling[i]);
479                 };
480                 ^time * sign;
481         }
483         speak { arg channel = 0, force = false;
484                 var speech = GUI.current.speech;
485                 if( speech.initialized.not, { speech.init });
486                 speech.channels[ channel ].speak( this, force );
487         }
489         toLower {
490                 ^this.collect(_.toLower)
491         }
492         toUpper {
493                 ^this.collect(_.toUpper)
494         }