├── .gitignore ├── LICENSE ├── README.md ├── dub.json ├── linux.mak ├── makefile ├── me.html ├── src └── med │ ├── ansicolors.d │ ├── basic.d │ ├── buffer.d │ ├── console.d │ ├── disp.d │ ├── display.d │ ├── disprev.d │ ├── ed.d │ ├── file.d │ ├── fileio.d │ ├── line.d │ ├── main.d │ ├── more.d │ ├── mouse.d │ ├── random.d │ ├── regexp.d │ ├── region.d │ ├── search.d │ ├── spawn.d │ ├── syntaxc.d │ ├── syntaxcpp.d │ ├── syntaxd.d │ ├── tcap.d │ ├── terminal.d │ ├── termio.d │ ├── testkbd.d │ ├── url.d │ ├── utf.d │ ├── window.d │ ├── word.d │ └── xterm.d └── win32.mak /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.obj 3 | .B* 4 | *~ 5 | bin 6 | obj 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This version of microEmacs is based on the public domain C 2 | version written by Dave G. Conroy. 3 | The D programming language version is written by Walter Bright. 4 | This program is in the public domain. 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ## med, Micro Emacs in D 3 | 4 | This is my version of MicroEmacs, based on the public 5 | domain version by Dave Conroy. I like it because it is 6 | small, fast, easilly customizable, and it ports readilly 7 | to whatever machine I need to use it on. It's written 8 | in the [D programming language](https://dlang.org). 9 | 10 | It currently works on Windows and Linux. 11 | 12 | To edit myfile.d: 13 | ``` 14 | med myfile.d 15 | ``` 16 | 17 | Cheat Sheet 18 | ``` 19 | Command Name Description Keybinding 20 | 21 | Movement 22 | 23 | basic_nextline Move to next line F5 24 | gotobol Move to start of line ^A 25 | forwchar Move forward by characters ^F, rightarrow 26 | gotoeol Move to end of line ^E 27 | backchar Move backward by characters ^B, leftarrow 28 | forwline Move forward by lines ^N, downarrow 29 | backline Move backward by lines ^P, uparrow 30 | forwpage Move forward by pages ^V, PgDn 31 | backpage Move backward by pages Esc B, PgUp 32 | gotobob Move to start of buffer Esc <, ^Home 33 | gotoeob Move to end of buffer Esc >, ^End 34 | gotoline Move to line number ^X L 35 | word_back Backup by words Esc B, ^leftarrow 36 | word_forw Advance by words Esc F, ^rightarrow 37 | 38 | Windows 39 | 40 | window_next Move to the next window ^X N, F6 41 | window_prev Move to the previous window ^X P 42 | window_only Make current window only one ^X 1 43 | window_split Split current window ^X 2 44 | window_mvdn Move window down Esc N, End 45 | window_mvup Move window up Esc P, Home 46 | window_enlarge Enlarge display window ^X Z 47 | window_shrink Shrink window Esc Z 48 | window_reposition Reposition window ^X T 49 | window_refresh Refresh the screen ^L 50 | delwind Delete a window ^X D 51 | 52 | Deleting 53 | 54 | random_deblank Delete blank lines ^X O 55 | random_forwdel Forward delete ^D, Del 56 | random_backdel Backward delete ^H, 0x7F 57 | random_undelchar Undelete a character AltF Del 58 | Ddelline Delete a line ^J 59 | Dundelline Undelete a line Esc J, AltF F2 60 | Ddelword Delete a word 61 | Ddelbword Delete a word (backwards) 62 | Dundelword Undelete a word AltF ^rightarrow, AltF ^leftarrow 63 | delfword Delete forward word Esc D 64 | delbword Delete backward word Esc H 65 | 66 | Cutting/Pasting 67 | 68 | random_kill Kill forward ^K 69 | random_yank Paste from kill buffer ^Y, ^X K, F10 70 | region_kill Cut region to kill buffer Esc 9, F9 71 | region_copy Copy region to kill buffer Esc 8, F8 72 | basic_setmark Set mark F7, Esc . 73 | removemark Remove mark ^X . 74 | swapmark Swap dot and mark Esc X 75 | word_select Select word Esc W 76 | 77 | Files 78 | 79 | filenext Edit next file AltF N 80 | fileread Get a file, read only AltF R 81 | filevisit Get a file, read write AltF V 82 | filewrite Write a file AltF W 83 | fileunmodify Turn off buffer changed bits AltF U 84 | filesave Save current file AltF S 85 | filename Adjust file name AltF F 86 | filemodify Write modified files AltF M 87 | Dinsertfile Insert a file at dot AltF I 88 | 89 | Exit 90 | 91 | ctrlg Abort out of things ^@, ^G 92 | quit Quit ^C, AltF Q 93 | quickexit low keystroke style exit 94 | normexit Write modified files and exit AltF X, AltX 95 | 96 | Macros 97 | 98 | ctlxlp Begin macro ^X ( 99 | ctlxrp End macro ^X ) 100 | macrotoggle Start/End macro F12 101 | ctlxe Execute macro ^X E, F11 102 | 103 | Search 104 | 105 | forwsearch Search forward ^S 106 | Search forward regexp ^S^T 107 | Search forward word ^S^W 108 | backsearch Search backwards ^R 109 | replacestring Search and replace Esc R 110 | queryreplacestring Query search and replace Esc Q 111 | Dsearch Search F4, AltF F4 112 | Dsearchagain Search for the same string F2 113 | 114 | D, C and C++ 115 | 116 | search_paren Toggle over parentheses ^W, F3 117 | random_indent Insert CR-LF, then indent 118 | random_incindent increase indentation level ^X ], AltF10 119 | random_decindent decrease indentation level ^X [, AltF9 120 | random_opttab optimize tabbing in line Esc I 121 | Dcppcomment convert /* */ to // ^X / 122 | 123 | Configuration 124 | 125 | display_norm_fg AltF2 126 | display_norm_bg AltF1 127 | display_mode_fg AltF4 128 | display_mode_bg AltF3 129 | display_mark_fg AltF5 130 | display_mark_bg AltF6 131 | display_eol_bg AltF7 132 | main_saveconfig Save configuration AltC 133 | 134 | Process 135 | 136 | spawncli Run CLI in a subjob ^Z 137 | spawn Run a command in a subjob ^X ! 138 | spawn_filter Filter buffer through program ^X # 139 | spawn_pipe Run program and gather output ^X @, AltZ 140 | Dpause Pause the program (UNIX only) 141 | 142 | Buffers 143 | 144 | listbuffers Display list of buffers AltF B 145 | usebuffer Switch a window to a buffer ^X B 146 | buffer_next Switch to next buffer ^X W, AltB 147 | killbuffer Make a buffer go away 148 | 149 | Other 150 | 151 | random_setfillcol Set fill column ^X F 152 | word_wrap_line Word wrap line ^X A 153 | random_showcpos Show the cursor position ^X = 154 | random_twiddle Twiddle characters ^T 155 | random_tab Insert tab ^I, Tab 156 | random_hardtab Set hardware tabs AltF T 157 | random_newline Insert CR-LF ^M 158 | random_openline Open up a blank line ^O, AltF Ins 159 | random_quote Insert literal ^Q, ^X Q 160 | region_togglemode Toggle column region mode Esc T 161 | toggleinsert Toggle insert/overwrite mode Ins 162 | line_overwrite Write char in overwrite mode 163 | getcol Get current column 164 | misc_upper Upper case word/region Esc U 165 | misc_lower Lower case word/region Esc L 166 | capword Initial capitalize word Esc C 167 | win32toggle43 Toggle hires mode AltE 168 | ibmpctoggle43 Toggle hires mode AltE 169 | Dignore do nothing 170 | Dadvance Set into advance mode Esc downarrow 171 | Dbackup Set into backup mode Esc uparrow 172 | Dinsertdate File and date stamp AltF D 173 | scrollUnicode Scroll through Unicode variations ^X U 174 | ``` 175 | 176 | ### Glossary 177 | 178 | * *dot* current cursor position 179 | * *mark* start of a region 180 | * *minibuffer* text entry box used for entering file names 181 | and search strings 182 | * *region* text between "dot" and "mark" 183 | * [Regular Expressions](https://www.digitalmars.com/ctg/regular.html) 184 | 185 | 186 | ### Notes 187 | 188 | * ^[ also works as Esc. 189 | * Names without a keybinding can't be accessed, but they can 190 | be called if the keybindings in main.c are updated. 191 | * Prefixing a command with ^U enables a count to be entered, 192 | which executes the command count times. 193 | * Pressing ^X, AltF, or Esc and then pausing will bring up 194 | a menu. 195 | * The right mouse button will bring up a menu. 196 | * The left mouse button can be used for setting the dot, 197 | marking regions, and adjusting window sizes. 198 | * The minibuffer has a small history buffer, accessible with 199 | the uparrow key. 200 | * On Win32, by clicking on the title bar, then select [Edit], 201 | you can access the Windows clipboard. This is very handy 202 | for cutting/pasting text from another window or the web browser. 203 | 204 | ### Bugs 205 | 206 | * Some of the keybindings make no sense. 207 | * The Alt function key sequences don't work on Win32. 208 | * The control numeric pad sequences don't work on Linux. 209 | * The colors can't be modified on any but the DOS version. 210 | * The process functionality is flaky. 211 | * For some reason, the mouse in the Win32 version doesn't 212 | work on Win2000, but does on WinNT. 213 | -------------------------------------------------------------------------------- /dub.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "med", 3 | "description": "MicroEmacs written in D", 4 | "authors": ["Dave G. Conroy", "Walter Bright"], 5 | "homepage": "https://github.com/DigitalMars/med", 6 | "license": "public domain", 7 | "targetType": "executable", 8 | "targetName": "med", 9 | "targetPath": "bin", 10 | "sourcePaths": ["src/med"], 11 | "importPaths": ["src/med"], 12 | } 13 | -------------------------------------------------------------------------------- /linux.mak: -------------------------------------------------------------------------------- 1 | #_ linux.mak 2 | 3 | DMD=dmd 4 | MODEL=32 5 | S=src/med 6 | O=obj 7 | B=bin 8 | 9 | DFLAGS=-g -od$O -I$S -m$(MODEL) 10 | LDFLG=-g \ 11 | -L~/cbx/mars/phobos/generated/linux/release/32 \ 12 | -L~/cbx/mars/phobos/generated/linux/release/64 \ 13 | 14 | 15 | .d.o: 16 | $(DMD) -c $(DFLAGS) $* 17 | 18 | all: $B/med 19 | 20 | SRC= $S/ed.d $S/basic.d $S/buffer.d $S/display.d $S/file.d $S/fileio.d $S/line.d \ 21 | $S/random.d $S/region.d $S/search.d $S/spawn.d $S/terminal.d \ 22 | $S/window.d $S/word.d $S/main.d $S/more.d $S/disprev.d \ 23 | $S/syntaxd.d $S/syntaxc.d $S/syntaxcpp.d $S/termio.d $S/xterm.d \ 24 | $S/tcap.d $S/console.d $S/mouse.d $S/disp.d $S/url.d $S/utf.d $S/regexp.d 25 | 26 | 27 | OBJ= $O/ed.o $O/basic.o $O/buffer.o $O/display.o $O/file.o $O/fileio.o $O/line.o \ 28 | $O/random.o $O/region.o $O/search.o $O/spawn.o $O/terminal.o \ 29 | $O/window.o $O/word.o $O/main.o $O/more.o $O/disprev.o \ 30 | $O/syntaxd.o $O/syntaxc.o $O/syntaxcpp.o $O/termio.o $O/xterm.o \ 31 | $O/tcap.o $O/console.o $O/mouse.o $O/disp.o $O/url.o $O/utf.o $O/regexp.o 32 | 33 | SOURCE= $(SRC) win32.mak linux.mak me.html 34 | 35 | $B/med : $(OBJ) linux.mak 36 | $(DMD) $(DFLAGS) -of$B/med $(OBJ) 37 | 38 | ansicolors : $S/ansicolors.d 39 | $(DMD) $(DFLAGS) -of$B/ansicolors $S/ansicolors.d 40 | 41 | $O/ed.o: $S/ed.d 42 | $(DMD) -c $(DFLAGS) $S/ed.d 43 | 44 | $O/basic.o: $S/basic.d 45 | $(DMD) -c $(DFLAGS) $S/basic.d 46 | 47 | $O/buffer.o: $S/buffer.d 48 | $(DMD) -c $(DFLAGS) $S/buffer.d 49 | 50 | $O/console.o: $S/console.d 51 | $(DMD) -c $(DFLAGS) $S/console.d 52 | 53 | $O/disp.o: $S/disp.d 54 | $(DMD) -c $(DFLAGS) $S/disp.d 55 | 56 | $O/display.o: $S/display.d 57 | $(DMD) -c $(DFLAGS) $S/display.d 58 | 59 | $O/file.o: $S/file.d 60 | $(DMD) -c $(DFLAGS) $S/file.d 61 | 62 | $O/fileio.o: $S/fileio.d 63 | $(DMD) -c $(DFLAGS) $S/fileio.d 64 | 65 | $O/line.o: $S/line.d 66 | $(DMD) -c $(DFLAGS) $S/line.d 67 | 68 | $O/mouse.o: $S/mouse.d 69 | $(DMD) -c $(DFLAGS) $S/mouse.d 70 | 71 | $O/random.o: $S/random.d 72 | $(DMD) -c $(DFLAGS) $S/random.d 73 | 74 | $O/regexp.o: $S/regexp.d 75 | $(DMD) -c $(DFLAGS) $S/regexp.d 76 | 77 | $O/region.o: $S/region.d 78 | $(DMD) -c $(DFLAGS) $S/region.d 79 | 80 | $O/search.o: $S/search.d 81 | $(DMD) -c $(DFLAGS) $S/search.d 82 | 83 | $O/spawn.o: $S/spawn.d 84 | $(DMD) -c $(DFLAGS) $S/spawn.d 85 | 86 | $O/terminal.o: $S/terminal.d 87 | $(DMD) -c $(DFLAGS) $S/terminal.d 88 | 89 | $O/termio.o: $S/termio.d 90 | $(DMD) -c $(DFLAGS) $S/termio.d 91 | 92 | $O/url.o: $S/url.d 93 | $(DMD) -c $(DFLAGS) $S/url.d 94 | 95 | $O/window.o: $S/window.d 96 | $(DMD) -c $(DFLAGS) $S/window.d 97 | 98 | $O/word.o: $S/word.d 99 | $(DMD) -c $(DFLAGS) $S/word.d 100 | 101 | $O/main.o: $S/main.d 102 | $(DMD) -c $(DFLAGS) $S/main.d 103 | 104 | $O/more.o: $S/more.d 105 | $(DMD) -c $(DFLAGS) $S/more.d 106 | 107 | $O/disprev.o: $S/disprev.d 108 | $(DMD) -c $(DFLAGS) $S/disprev.d 109 | 110 | $O/syntaxd.o: $S/syntaxd.d 111 | $(DMD) -c $(DFLAGS) $S/syntaxd.d 112 | 113 | $O/syntaxc.o: $S/syntaxc.d 114 | $(DMD) -c $(DFLAGS) $S/syntaxc.d 115 | 116 | $O/syntaxcpp.o: $S/syntaxcpp.d 117 | $(DMD) -c $(DFLAGS) $S/syntaxcpp.d 118 | 119 | $O/tcap.o: $S/tcap.d 120 | $(DMD) -c $(DFLAGS) $S/tcap.d 121 | 122 | $O/utf.o: $S/utf.d 123 | $(DMD) -c $(DFLAGS) $S/utf.d 124 | 125 | $O/xterm.o: $S/xterm.d 126 | $(DMD) -c $(DFLAGS) $S/xterm.d 127 | 128 | clean: 129 | rm $O/*.o 130 | 131 | detab : $(SRC) 132 | detab $(SRC) 133 | 134 | zip : $(SOURCE) 135 | rm -f me.zip 136 | zip me $(SOURCE) 137 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | MODEL=32 2 | 3 | #HOST_DMD=/usr/bin/dmd 4 | #HOST_DMD=/home/walter/dmd2.067/linux/bin64/dmd 5 | #HOST_DMD=/home/walter/dmd2.074.1/linux/bin64/dmd 6 | #HOST_DMD=/home/walter/dmd2.079.1/linux/bin64/dmd 7 | HOST_DMD=/home/walter/dmd2.089.1/linux/bin64/dmd 8 | #HOST_DMD=/home/walter/cbx/mars/dmd2 9 | #HOST_DMD=/home/walter/forks/dmd/generated/linux/release/64/dmd 10 | 11 | MAKE=make DMD=$(HOST_DMD) MODEL=$(MODEL) -f linux.mak 12 | 13 | targets: 14 | $(MAKE) 15 | 16 | ansicolors: 17 | $(MAKE) ansicolors 18 | 19 | detab: 20 | $(MAKE) detab 21 | 22 | clean: 23 | $(MAKE) clean 24 | 25 | zip: 26 | $(MAKE) zip 27 | -------------------------------------------------------------------------------- /me.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Digital Mars - MicroEmacs (Text Editor) 5 | 6 | 7 | 8 | www.digitalmars.com 9 | [Home] 10 | [Search] 11 | [CTG] 12 | [RTL] 13 | [IDDE] 14 | [STL] 15 | [Shop] 16 |
17 | 18 |

MicroEmacs

19 | 20 | This is my version of MicroEmacs, based on the public 21 | domain version by Dave Conroy. I like it because it is 22 | small, fast, easilly customizable, and it ports readilly 23 | to whatever machine I need to use it on. 24 |

25 | 26 | This version is also in the public domain. 27 | 28 |

 29 | 	-Walter Bright
 30 | 	www.digitalmars.com
 31 | 
 32 | 
 33 | 	men.exe		Win32 executable
 34 | 	mex.exe		DOS32 executable
 35 | 	medos.exe	DOS executable
 36 | 	melinux		Linux executable
 37 | 
 38 | Command Name         Description                        Keybinding
 39 | 
 40 | Movement
 41 | 
 42 | basic_nextline       Move to next line			F5
 43 | gotobol              Move to start of line		^A
 44 | forwchar             Move forward by characters		^F, rightarrow
 45 | gotoeol              Move to end of line		^E
 46 | backchar             Move backward by characters	^B, leftarrow
 47 | forwline             Move forward by lines		^N, downarrow
 48 | backline             Move backward by lines		^P, uparrow
 49 | forwpage             Move forward by pages		^V, PgDn
 50 | backpage             Move backward by pages		Esc B, PgUp
 51 | gotobob              Move to start of buffer		Esc <, ^Home
 52 | gotoeob              Move to end of buffer		Esc >, ^End
 53 | gotoline             Move to line number		^X L
 54 | word_back            Backup by words			Esc B, ^leftarrow
 55 | word_forw            Advance by words			Esc F, ^rightarrow
 56 | 
 57 | Windows
 58 | 
 59 | window_next          Move to the next window		^X N, F6
 60 | window_prev          Move to the previous window	^X P
 61 | window_only          Make current window only one	^X 1
 62 | window_split         Split current window		^X 2
 63 | window_mvdn          Move window down			Esc N, End
 64 | window_mvup          Move window up			Esc P, Home
 65 | window_enlarge       Enlarge display window		^X Z
 66 | window_shrink        Shrink window			Esc Z
 67 | window_reposition    Reposition window			^X T
 68 | window_refresh       Refresh the screen			^L
 69 | delwind              Delete a window			^X D
 70 | 
 71 | Deleting
 72 | 
 73 | random_deblank       Delete blank lines			^X O
 74 | random_forwdel       Forward delete			^D, Del
 75 | random_backdel       Backward delete			^H, 0x7F
 76 | random_undelchar     Undelete a character		AltF Del
 77 | Ddelline             Delete a line			^J
 78 | Dundelline           Undelete a line			Esc J, AltF F2
 79 | Ddelword             Delete a word
 80 | Ddelbword            Delete a word (backwards)
 81 | Dundelword           Undelete a word			AltF ^rightarrow, AltF ^leftarrow
 82 | delfword             Delete forward word		Esc D
 83 | delbword             Delete backward word		Esc H
 84 | 
 85 | Cutting/Pasting
 86 | 
 87 | random_kill          Kill forward			^K
 88 | random_yank          Paste from kill buffer		^Y, ^X K, F10
 89 | region_kill          Cut region to kill buffer		Esc 9, F9
 90 | region_copy          Copy region to kill buffer		Esc 8, F8
 91 | basic_setmark        Set mark				F7, Esc .
 92 | removemark           Remove mark			^X .
 93 | swapmark             Swap dot and mark			Esc X
 94 | word_select          Select word			Esc W
 95 | 
 96 | Files
 97 | 
 98 | filenext             Edit next file			AltF N
 99 | fileread             Get a file, read only		AltF R
100 | filevisit            Get a file, read write		AltF V
101 | filewrite            Write a file			AltF W
102 | fileunmodify         Turn off buffer changed bits	AltF U
103 | filesave             Save current file			AltF S
104 | filename             Adjust file name			AltF F
105 | filemodify           Write modified files		AltF M
106 | Dinsertfile          Insert a file at dot		AltF I
107 | 
108 | Exit
109 | 
110 | ctrlg                Abort out of things		^@, ^G
111 | quit                 Quit				^C, AltF Q
112 | quickexit            low keystroke style exit
113 | normexit             Write modified files and exit	AltF X, AltX
114 | 
115 | Macros
116 | 
117 | ctlxlp               Begin macro			^X (
118 | ctlxrp               End macro				^X )
119 | macrotoggle          Start/End macro			F12
120 | ctlxe                Execute macro			^X E, F11
121 | 
122 | Search
123 | 
124 | forwsearch           Search forward			^S
125 |                      Search forward regexp              ^S^T
126 |                      Search forward word                ^S^W
127 | backsearch           Search backwards			^R
128 | replacestring        Search and replace			Esc R
129 | queryreplacestring   Query search and replace		Esc Q
130 | Dsearch              Search				F4, AltF F4
131 | Dsearchagain         Search for the same string		F2
132 | 
133 | C and C++
134 | 
135 | search_paren         Toggle over parentheses		^W, F3
136 | random_indent        Insert CR-LF, then indent
137 | random_incindent     increase indentation level		^X ], AltF10
138 | random_decindent     decrease indentation level		^X [, AltF9
139 | random_opttab        optimize tabbing in line		Esc I
140 | Dcppcomment          convert /* */ to //		^X /
141 | 
142 | Configuration
143 | 
144 | display_norm_fg						AltF2
145 | display_norm_bg						AltF1
146 | display_mode_fg						AltF4
147 | display_mode_bg						AltF3
148 | display_mark_fg						AltF5
149 | display_mark_bg						AltF6
150 | display_eol_bg						AltF7
151 | main_saveconfig      Save configuration			AltC
152 | 
153 | Process
154 | 
155 | spawncli             Run CLI in a subjob		^Z
156 | spawn                Run a command in a subjob		^X !
157 | spawn_filter         Filter buffer through program	^X #
158 | spawn_pipe           Run program and gather output	^X @, AltZ
159 | Dpause               Pause the program (UNIX only)
160 | 
161 | Buffers
162 | 
163 | listbuffers          Display list of buffers		AltF B
164 | usebuffer            Switch a window to a buffer	^X B
165 | buffer_next          Switch to next buffer		^X W, AltB
166 | killbuffer           Make a buffer go away
167 | 
168 | Other
169 | 
170 | random_setfillcol    Set fill column			^X F
171 | word_wrap_line       Word wrap line                     ^X A
172 | random_showcpos      Show the cursor position		^X =
173 | random_twiddle       Twiddle characters			^T
174 | random_tab           Insert tab				^I, Tab
175 | random_hardtab       Set hardware tabs			AltF T
176 | random_newline       Insert CR-LF			^M
177 | random_openline      Open up a blank line		^O, AltF Ins
178 | random_quote         Insert literal			^Q, ^X Q
179 | region_togglemode    Toggle column region mode		Esc T
180 | toggleinsert         Toggle insert/overwrite mode	Ins
181 | line_overwrite       Write char in overwrite mode
182 | getcol               Get current column
183 | misc_upper           Upper case word/region		Esc U
184 | misc_lower           Lower case word/region		Esc L
185 | capword              Initial capitalize word		Esc C
186 | win32toggle43        Toggle hires mode			AltE
187 | ibmpctoggle43        Toggle hires mode			AltE
188 | Dignore              do nothing
189 | Dadvance             Set into advance mode		Esc downarrow
190 | Dbackup              Set into backup mode		Esc uparrow
191 | Dinsertdate          File and date stamp		AltF D
192 | scrollUnicode        Scroll through Unicode variations  ^X U
193 | 
194 | 195 |

Glossary

196 | 197 |
198 |
dot
current cursor position 199 |
mark
start of a region 200 |
minibuffer
text entry box used for entering file names 201 | and search strings 202 |
region
text between "dot" and "mark" 203 |
Regular Expressions 204 |
205 | 206 |

Notes

207 | 208 | 225 | 226 |

Bugs

227 | 228 | 237 | 238 | 239 | 240 | -------------------------------------------------------------------------------- /src/med/ansicolors.d: -------------------------------------------------------------------------------- 1 | /******************************************* 2 | * Print various ANSI escape sequences to the screen. 3 | */ 4 | 5 | module ansicolors; 6 | 7 | import core.stdc.stdio; 8 | 9 | void main() 10 | { 11 | // Escape sequences: 12 | // https://stackoverflow.com/questions/4842424/list-of-ansi-color-escape-sequences 13 | // https://opensource.com/article/19/9/linux-terminal-colors 14 | 15 | string s = "text sequence"; 16 | foreach (i; 30 .. 37+1) 17 | { 18 | printf("\\033[%dm \033[%dm %s\n", i, i, s.ptr); 19 | resetColor(); 20 | } 21 | foreach (i; 30 .. 37+1) 22 | { 23 | printf("\\033[1;%dm \033[1;%dm %s\n", i, i, s.ptr); 24 | resetColor(); 25 | } 26 | foreach (i; 40 .. 47+1) 27 | { 28 | printf("\\033[%dm \033[%dm %s", i, i, s.ptr); 29 | resetColor(); 30 | printf("\n"); 31 | } 32 | foreach (i; 0 .. 10+1) 33 | { 34 | printf("\\033[%d;30m \033[%d;30m %s\n", i, i, s.ptr); 35 | resetColor(); 36 | } 37 | foreach (i; 51 .. 53+1) 38 | { 39 | printf("\\033[%d;30m \033[%d;30m %s\n", i, i, s.ptr); 40 | resetColor(); 41 | } 42 | } 43 | 44 | void resetColor() 45 | { 46 | fputs("\033[m", stdout); 47 | } 48 | 49 | -------------------------------------------------------------------------------- /src/med/basic.d: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* This version of microEmacs is based on the public domain C 4 | * version written by Dave G. Conroy. 5 | * The D programming language version is written by Walter Bright. 6 | * http://www.digitalmars.com/d/ 7 | * This program is in the public domain. 8 | */ 9 | 10 | /* 11 | * The routines in this file move the cursor around on the screen. They 12 | * compute a new value for the cursor, then adjust ".". The display code 13 | * always updates the cursor location, so only moves between lines, or 14 | * functions that adjust the top line in the window and invalidate the 15 | * framing, are hard. 16 | */ 17 | 18 | module basic; 19 | 20 | import std.conv; 21 | 22 | import ed; 23 | import line; 24 | import main; 25 | import window; 26 | import display; 27 | import console; 28 | 29 | /********************************* 30 | * Move the cursor to the 31 | * beginning of the current line. 32 | * Trivial. 33 | */ 34 | 35 | int gotobol(bool f, int n) 36 | { int s; 37 | 38 | if (curwp.w_doto == 0) 39 | s = backline(f, n); 40 | else 41 | { 42 | if (curwp.w_markp) 43 | curwp.w_flag |= WFMOVE; 44 | s = TRUE; 45 | curwp.w_doto = 0; 46 | if( n > 1 ) 47 | s = backline(f, n-1); 48 | } 49 | curgoal = 0; 50 | return s; 51 | } 52 | 53 | /* 54 | * Move the cursor backwards by "n" characters. If "n" is less than zero call 55 | * "forwchar" to actually do the move. Otherwise compute the new cursor 56 | * location. Error if you try and move out of the buffer. Set the flag if the 57 | * line pointer for dot changes. 58 | */ 59 | int backchar(bool f, int n) 60 | { 61 | if (n < 0) 62 | return (forwchar(f, -n)); 63 | if (curwp.w_markp && n) 64 | curwp.w_flag |= WFMOVE; 65 | while (n--) { 66 | if (curwp.w_doto == 0) { 67 | LINE *lp; 68 | if ((lp=lback(curwp.w_dotp)) == curbp.b_linep) 69 | return (FALSE); 70 | curwp.w_dotp = lp; 71 | curwp.w_doto = llength(lp); 72 | curwp.w_flag |= WFMOVE; 73 | } else 74 | curwp.w_doto--; 75 | } 76 | return (TRUE); 77 | } 78 | 79 | /************************************** 80 | * Move the cursor to the end of the current line. 81 | * If already at the end, advance to next line. 82 | */ 83 | 84 | int gotoeol(bool f, int n) 85 | { 86 | int s; 87 | 88 | s = TRUE; 89 | if( curwp.w_doto != llength(curwp.w_dotp) ) 90 | { 91 | if (curwp.w_markp) 92 | curwp.w_flag |= WFMOVE; 93 | n--; 94 | } 95 | if( n > 0 ) 96 | s = forwline(f,n); 97 | curwp.w_doto = llength(curwp.w_dotp); 98 | return( s ); 99 | } 100 | 101 | /* 102 | * Move the cursor forwards by "n" characters. If "n" is less than zero call 103 | * "backchar" to actually do the move. Otherwise compute the new cursor 104 | * location, and move ".". Error if you try and move off the end of the 105 | * buffer. Set the flag if the line pointer for dot changes. 106 | */ 107 | int forwchar(bool f, int n) 108 | { 109 | if (n < 0) 110 | return (backchar(f, -n)); 111 | if (curwp.w_markp && n) 112 | curwp.w_flag |= WFMOVE; 113 | while (n--) { 114 | if (curwp.w_doto == llength(curwp.w_dotp)) { 115 | if (curwp.w_dotp == curbp.b_linep) 116 | return (FALSE); 117 | curwp.w_dotp = lforw(curwp.w_dotp); 118 | curwp.w_doto = 0; 119 | curwp.w_flag |= WFMOVE; 120 | } else 121 | curwp.w_doto++; 122 | } 123 | return (TRUE); 124 | } 125 | 126 | /* 127 | * Goto the beginning of the buffer. Massive adjustment of dot. This is 128 | * considered to be hard motion; it really isn't if the original value of dot 129 | * is the same as the new value of dot. Normally bound to "M-<". 130 | */ 131 | int gotobob(bool f, int n) 132 | { 133 | curwp.w_dotp = lforw(curbp.b_linep); 134 | curwp.w_doto = 0; 135 | curwp.w_flag |= WFHARD; 136 | return (TRUE); 137 | } 138 | 139 | /* 140 | * Move to the end of the buffer. Dot is always put at the end of the file 141 | * (ZJ). The standard screen code does most of the hard parts of update. 142 | * Bound to "M.". 143 | */ 144 | int gotoeob(bool f, int n) 145 | { 146 | curwp.w_dotp = curbp.b_linep; 147 | curwp.w_doto = 0; 148 | curwp.w_flag |= WFHARD; 149 | return (TRUE); 150 | } 151 | 152 | /* 153 | * Move forward by full lines. If the number of lines to move is less than 154 | * zero, call the backward line function to actually do it. The last command 155 | * controls how the goal column is set. Bound to "C-N". No errors are 156 | * possible. 157 | */ 158 | int forwline(bool f, int n) 159 | { 160 | if (n < 0) 161 | return (backline(f, -n)); 162 | auto dlp = curwp.w_dotp; 163 | 164 | /* Reset goal if last command not backline() or forwline() */ 165 | if ((lastflag&CFCPCN) == 0) 166 | curgoal = getcol(dlp,curwp.w_doto); 167 | thisflag |= CFCPCN; /* this command was a */ 168 | /* forwline or backline */ 169 | while (n-- && dlp!=curbp.b_linep) 170 | dlp = lforw(dlp); 171 | curwp.w_dotp = dlp; 172 | curwp.w_doto = getgoal(dlp); 173 | curwp.w_flag |= WFMOVE; 174 | return (TRUE); 175 | } 176 | 177 | /******************************* 178 | * Proceed to beginning of next line. 179 | */ 180 | 181 | int basic_nextline(bool f, int n) 182 | { 183 | if (curwp.w_doto == 0 || gotobol(FALSE,1)) 184 | { 185 | lastflag &= ~CFCPCN; 186 | return forwline(f,n); 187 | } 188 | return FALSE; 189 | } 190 | 191 | /* 192 | * This function is like "forwline", but goes backwards. The scheme is exactly 193 | * the same. Check for arguments that are less than zero and call your 194 | * alternate. Figure out the new line and call "movedot" to perform the 195 | * motion. No errors are possible. Bound to "C-P". 196 | */ 197 | int backline(bool f, int n) 198 | { 199 | if (n < 0) 200 | return (forwline(f, -n)); 201 | auto dlp = curwp.w_dotp; 202 | 203 | /* Reset goal if last command not backline() or forwline() */ 204 | if ((lastflag&CFCPCN) == 0) 205 | curgoal = getcol(dlp,curwp.w_doto); 206 | thisflag |= CFCPCN; 207 | 208 | while (n-- && lback(dlp)!=curbp.b_linep) 209 | dlp = lback(dlp); 210 | curwp.w_dotp = dlp; 211 | curwp.w_doto = getgoal(dlp); 212 | curwp.w_flag |= WFMOVE; 213 | return (TRUE); 214 | } 215 | 216 | /********************************** 217 | * Goto line number. 218 | */ 219 | 220 | int gotoline(bool f, int n) 221 | { string number; 222 | 223 | if (mlreply("Goto line: ", null, number) == FALSE) 224 | return FALSE; 225 | try 226 | { 227 | const num = to!(int)(number); 228 | gotobob(f, n); /* move to beginning of buffer */ 229 | return forwline(f, num - 1); 230 | } 231 | catch (Throwable o) 232 | { 233 | } 234 | return FALSE; 235 | } 236 | 237 | /* 238 | * This routine, given a pointer to a LINE, and the current cursor goal 239 | * column, return the best choice for the offset. The offset is returned. 240 | * Used by forwline() and backline(). 241 | */ 242 | int getgoal(LINE* dlp) 243 | { 244 | int c; 245 | int col; 246 | int newcol; 247 | int dbo; 248 | 249 | col = 0; 250 | dbo = 0; 251 | while (dbo != llength(dlp)) { 252 | c = lgetc(dlp, dbo); 253 | newcol = col; 254 | if (c == '\t') 255 | newcol |= 0x07; 256 | else if (c<0x20 || c==0x7F) 257 | ++newcol; 258 | ++newcol; 259 | if (newcol > curgoal) 260 | break; 261 | col = newcol; 262 | ++dbo; 263 | } 264 | return (dbo); 265 | } 266 | 267 | /* 268 | * Scroll forward by a specified number of lines, or by a full page if no 269 | * argument. Bound to "C-V". The "2" in the arithmetic on the window size is 270 | * the overlap; this value is the default overlap value in ITS EMACS. Because 271 | * this zaps the top line in the display window, we have to do a hard update. 272 | */ 273 | int forwpage(bool f, int n) 274 | { 275 | if (f == FALSE) { 276 | n = curwp.w_ntrows - 2; /* Default scroll. */ 277 | if (n <= 0) /* Forget the overlap */ 278 | n = 1; /* if tiny window. */ 279 | } else if (n < 0) 280 | return (backpage(f, -n)); 281 | else if (CVMVAS) /* Convert from pages */ 282 | n *= curwp.w_ntrows; /* to lines. */ 283 | auto lp = curwp.w_linep; 284 | while (n-- && lp!=curbp.b_linep) 285 | lp = lforw(lp); 286 | curwp.w_linep = lp; 287 | curwp.w_dotp = lp; 288 | curwp.w_doto = 0; 289 | curwp.w_flag |= WFHARD; 290 | return (TRUE); 291 | } 292 | 293 | /* 294 | * This command is like "forwpage", but it goes backwards. The "2", like 295 | * above, is the overlap between the two windows. The value is from the ITS 296 | * EMACS manual. Bound to "M-V". We do a hard update for exactly the same 297 | * reason. 298 | */ 299 | int backpage(bool f, int n) 300 | { 301 | if (f == FALSE) { 302 | n = curwp.w_ntrows - 2; /* Default scroll. */ 303 | if (n <= 0) /* Don't blow up if the */ 304 | n = 1; /* window is tiny. */ 305 | } else if (n < 0) 306 | return (forwpage(f, -n)); 307 | else if (CVMVAS) /* Convert from pages */ 308 | n *= curwp.w_ntrows; /* to lines. */ 309 | auto lp = curwp.w_linep; 310 | while (n-- && lback(lp)!=curbp.b_linep) 311 | lp = lback(lp); 312 | curwp.w_linep = lp; 313 | curwp.w_dotp = lp; 314 | curwp.w_doto = 0; 315 | curwp.w_flag |= WFHARD; 316 | return (TRUE); 317 | } 318 | 319 | /* 320 | * Set the mark in the current window to the value of "." in the window. No 321 | * errors are possible. Bound to "M-.". 322 | */ 323 | int basic_setmark(bool f, int n) 324 | { 325 | removemark(f,n); /* delete old mark */ 326 | curwp.w_markp = curwp.w_dotp; 327 | curwp.w_marko = curwp.w_doto; 328 | /* Get starting column for column regions */ 329 | markcol = getcol(curwp.w_markp,curwp.w_doto); 330 | mlwrite("[Mark set]"); 331 | return (TRUE); 332 | } 333 | 334 | /************************* 335 | * Remove mark from current window. 336 | */ 337 | 338 | int removemark(bool f, int n) 339 | { 340 | if (curwp.w_markp) 341 | { curwp.w_flag |= WFHARD; 342 | curwp.w_markp = null; 343 | mlwrite("[Mark removed]"); 344 | } 345 | else 346 | mlwrite("[No mark]"); 347 | return (TRUE); 348 | } 349 | 350 | /* 351 | * Swap the values of "." and "mark" in the current window. This is pretty 352 | * easy, bacause all of the hard work gets done by the standard routine 353 | * that moves the mark about. The only possible error is "no mark". Bound to 354 | * "C-X C-X". 355 | */ 356 | int swapmark(bool f, int n) 357 | { 358 | if (curwp.w_markp == null) { 359 | mlwrite("No mark in this window"); 360 | return (FALSE); 361 | } 362 | auto odotp = curwp.w_dotp; 363 | auto odoto = curwp.w_doto; 364 | curwp.w_dotp = curwp.w_markp; 365 | curwp.w_doto = curwp.w_marko; 366 | curwp.w_markp = odotp; 367 | curwp.w_marko = odoto; 368 | curwp.w_flag |= WFMOVE; 369 | return (TRUE); 370 | } 371 | -------------------------------------------------------------------------------- /src/med/buffer.d: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* This version of microEmacs is based on the public domain C 4 | * version written by Dave G. Conroy. 5 | * The D programming language version is written by Walter Bright. 6 | * http://www.digitalmars.com/d/ 7 | * This program is in the public domain. 8 | */ 9 | 10 | /* 11 | * Buffer management. 12 | * Some of the functions are internal, 13 | * and some are actually attached to user 14 | * keys. Like everyone else, they set hints 15 | * for the display system. 16 | */ 17 | 18 | module buffer; 19 | 20 | import std.stdio; 21 | import std.path; 22 | 23 | import core.memory; 24 | 25 | import ed; 26 | import line; 27 | import display; 28 | import main; 29 | import window; 30 | 31 | 32 | /* 33 | * Text is kept in buffers. A buffer header, described below, exists for every 34 | * buffer in the system. The buffers are kept in a big list, so that commands 35 | * that search for a buffer by name can find the buffer header. There is a 36 | * safe store for the dot and mark in the header, but this is only valid if 37 | * the buffer is not being displayed (that is, if "b_nwnd" is 0). The text for 38 | * the buffer is kept in a circularly linked list of lines, with a pointer to 39 | * the header line in "b_linep". 40 | */ 41 | struct BUFFER { 42 | LINE* b_dotp; // Link to "." LINE structure 43 | uint b_doto; // Offset of "." in above LINE 44 | LINE* b_markp; // The same as the above two, 45 | uint b_marko; // but for the "mark" 46 | LINE* b_linep; // Link to the header LINE 47 | uint b_nwnd; // Count of windows on buffer 48 | ubyte b_flag; // Flags 49 | string b_fname; // File name 50 | string b_bname; // Buffer name 51 | Language b_lang = Language.text; // for color syntax highlighting 52 | 53 | /********************************** 54 | * Set filename associated with buffer. 55 | * Determine the language based on the filename. 56 | */ 57 | void setFilename(string fname) 58 | { 59 | if (filenameCmp(b_fname, fname)) 60 | { 61 | const lang = filenameCmp(extension(fname), ".d") == 0 ? Language.D : 62 | filenameCmp(extension(fname), ".di") == 0 ? Language.D : 63 | filenameCmp(extension(fname), ".c") == 0 ? Language.C : 64 | filenameCmp(extension(fname), ".cpp") == 0 ? Language.CPP : 65 | filenameCmp(extension(fname), ".c++") == 0 ? Language.CPP : 66 | Language.text; 67 | if (b_lang != lang) 68 | { 69 | b_lang = lang; 70 | } 71 | } 72 | b_fname = fname; 73 | } 74 | } 75 | 76 | enum 77 | { 78 | BFTEMP = 0x01, // Internal temporary buffer 79 | BFCHG = 0x02, // Changed since last write 80 | BFRDONLY = 0x04, // Buffer is read only 81 | BFNOCR = 0x08, // last line in buffer has no 82 | // trailing CR 83 | } 84 | 85 | enum Language 86 | { 87 | text = 0, // plain text (must be 0) 88 | D, // D programming language 89 | C, // C programming language 90 | CPP, // C++ programming language 91 | } 92 | 93 | __gshared BUFFER*[] buffers; 94 | 95 | /* 96 | * Attach a buffer to a window. The 97 | * values of dot and mark come from the buffer 98 | * if the use count is 0. Otherwise, they come 99 | * from some other window. 100 | */ 101 | int usebuffer(bool f, int n) 102 | { 103 | string bufn; 104 | 105 | auto s = mlreply("Use buffer: ", null, bufn); 106 | if (s != TRUE) 107 | return (s); 108 | auto bp = buffer_find(bufn, TRUE, 0); 109 | if (bp == null) 110 | return (FALSE); 111 | return buffer_switch(bp); 112 | } 113 | 114 | /********************************* 115 | * Make next buffer in list the current one. 116 | * Put it into the current window if it isn't displayed. 117 | */ 118 | 119 | int buffer_next(bool f, int n) 120 | { 121 | foreach (i, bp; buffers) 122 | { 123 | if (bp == curbp) 124 | { 125 | i = i + 1; 126 | if (i == buffers.length) 127 | i = 0; 128 | return buffer_switch(buffers[i]); 129 | } 130 | } 131 | return FALSE; 132 | } 133 | 134 | /*************************** 135 | * Switch to buffer bp. 136 | * Returns: 137 | * TRUE or FALSE 138 | */ 139 | 140 | int buffer_switch(BUFFER* bp) 141 | { 142 | if (--curbp.b_nwnd == 0) { /* Last use. */ 143 | curbp.b_dotp = curwp.w_dotp; 144 | curbp.b_doto = curwp.w_doto; 145 | curbp.b_markp = curwp.w_markp; 146 | curbp.b_marko = curwp.w_marko; 147 | } 148 | curbp = bp; /* Switch. */ 149 | curwp.w_bufp = bp; 150 | curwp.w_linep = bp.b_linep; /* For macros, ignored. */ 151 | curwp.w_flag |= WFMODE|WFFORCE|WFHARD; /* Quite nasty. */ 152 | if (bp.b_nwnd++ == 0) { /* First use. */ 153 | curwp.w_dotp = bp.b_dotp; 154 | curwp.w_doto = bp.b_doto; 155 | curwp.w_markp = bp.b_markp; 156 | curwp.w_marko = bp.b_marko; 157 | return (TRUE); 158 | } 159 | else 160 | { 161 | /* Look for the existing window onto buffer bp */ 162 | foreach (wp; windows) 163 | { 164 | if (wp!=curwp && wp.w_bufp==bp) 165 | { 166 | curwp.w_dotp = wp.w_dotp; 167 | curwp.w_doto = wp.w_doto; 168 | curwp.w_markp = wp.w_markp; 169 | curwp.w_marko = wp.w_marko; 170 | break; 171 | } 172 | } 173 | } 174 | return TRUE; 175 | } 176 | 177 | /* 178 | * Dispose of a buffer, by name. 179 | * Ask for the name. Look it up (don't get too 180 | * upset if it isn't there at all!). Get quite upset 181 | * if the buffer is being displayed. Clear the buffer (ask 182 | * if the buffer has been changed). Then free the header 183 | * line and the buffer header. Bound to "C-X K". 184 | */ 185 | int killbuffer(bool f, int n) 186 | { 187 | BUFFER *bp; 188 | int s; 189 | string bufn; 190 | 191 | if ((s=mlreply("Kill buffer: ", null, bufn)) != TRUE) 192 | return (s); 193 | if ((bp=buffer_find(bufn, FALSE, 0)) == null) /* Easy if unknown. */ 194 | return (TRUE); 195 | return buffer_remove(bp); 196 | } 197 | 198 | /********************** 199 | * Remove buffer bp. 200 | * Returns: 201 | * 0 failed 202 | * !=0 succeeded 203 | */ 204 | 205 | int buffer_remove(BUFFER* bp) 206 | { 207 | if (bp.b_nwnd != 0) { /* Error if on screen. */ 208 | mlwrite("Buffer is being displayed"); 209 | return (FALSE); 210 | } 211 | if (!buffer_clear(bp)) /* Blow text away */ 212 | return FALSE; 213 | 214 | //delete bp.b_linep; /* Release header line. */ 215 | core.memory.GC.free(bp.b_linep); 216 | 217 | foreach (i, b; buffers) 218 | { 219 | if (b == bp) 220 | { 221 | buffers[i .. $ - 1] = buffers[i + 1 .. $]; 222 | buffers = buffers[0 .. $ - 1]; 223 | break; 224 | } 225 | } 226 | 227 | //delete bp; /* Release buffer block */ 228 | core.memory.GC.free(bp); 229 | 230 | return (TRUE); 231 | } 232 | 233 | /* 234 | * List all of the active 235 | * buffers. First update the special 236 | * buffer that holds the list. Next make 237 | * sure at least 1 window is displaying the 238 | * buffer list, splitting the screen if this 239 | * is what it takes. Lastly, repaint all of 240 | * the windows that are displaying the 241 | * list. Bound to "C-X C-B". 242 | */ 243 | int listbuffers(bool f, int n) 244 | { 245 | BUFFER *bp; 246 | int s; 247 | 248 | if ((s=makelist()) != TRUE) 249 | return (s); 250 | if (blistp.b_nwnd == 0) { /* Not on screen yet. */ 251 | WINDOW *wp; 252 | if ((wp=wpopup()) == null) 253 | return (FALSE); 254 | bp = wp.w_bufp; 255 | if (--bp.b_nwnd == 0) { 256 | bp.b_dotp = wp.w_dotp; 257 | bp.b_doto = wp.w_doto; 258 | bp.b_markp = wp.w_markp; 259 | bp.b_marko = wp.w_marko; 260 | } 261 | wp.w_bufp = blistp; 262 | ++blistp.b_nwnd; 263 | } 264 | foreach (wp; windows) 265 | { 266 | if (wp.w_bufp == blistp) { 267 | wp.w_linep = lforw(blistp.b_linep); 268 | wp.w_dotp = lforw(blistp.b_linep); 269 | wp.w_doto = 0; 270 | wp.w_markp = null; 271 | wp.w_marko = 0; 272 | wp.w_flag |= WFMODE|WFHARD; 273 | } 274 | } 275 | return (TRUE); 276 | } 277 | 278 | /* 279 | * This routine rebuilds the 280 | * text in the special secret buffer 281 | * that holds the buffer list. It is called 282 | * by the list buffers command. Return TRUE 283 | * if everything works. Return FALSE if there 284 | * is an error (if there is no memory). 285 | */ 286 | int makelist() 287 | { 288 | LINE *lp; 289 | int nbytes; 290 | int s; 291 | int type; 292 | char[6+1] b; 293 | char[128] line; 294 | 295 | blistp.b_flag &= ~BFCHG; /* Don't complain! */ 296 | if ((s=buffer_clear(blistp)) != TRUE) /* Blow old text away */ 297 | return (s); 298 | blistp.b_fname = null; 299 | if (addline("C Size Buffer File") == FALSE 300 | || addline("- ---- ------ ----") == FALSE) 301 | return (FALSE); 302 | /* For all buffers */ 303 | foreach (bp; buffers) 304 | { 305 | if ((bp.b_flag&BFTEMP) != 0) { /* Skip magic ones. */ 306 | continue; 307 | } 308 | int i = 0; /* Start at left edge */ 309 | if ((bp.b_flag&BFCHG) != 0) /* "*" if changed */ 310 | line[i++] = '*'; 311 | else 312 | line[i++] = ' '; 313 | line[i++] = ' '; /* Gap. */ 314 | nbytes = 0; /* Count bytes in buf. */ 315 | lp = lforw(bp.b_linep); 316 | while (lp != bp.b_linep) { 317 | nbytes += llength(lp)+1; 318 | lp = lforw(lp); 319 | } 320 | buffer_itoa(b, 6, nbytes); /* 6 digit buffer size. */ 321 | line[i .. i + b.length] = b; 322 | i += b.length; 323 | line[i++] = ' '; /* Gap. */ 324 | line[i .. i + bp.b_bname.length] = bp.b_bname; // buffer name 325 | i += bp.b_bname.length; 326 | if (bp.b_fname.length) 327 | { 328 | while (i < 25) 329 | line[i++] = ' '; 330 | line[i++] = ' '; 331 | foreach (c; bp.b_bname) 332 | { 333 | if (i < line.length) 334 | line[i++] = c; 335 | } 336 | } 337 | /* Add to the buffer. */ 338 | if (addline(line[0 .. i].idup) == FALSE) 339 | return (FALSE); 340 | } 341 | return (TRUE); /* All done */ 342 | } 343 | 344 | void buffer_itoa(char[] buf, int width, int num) 345 | { 346 | buf[width] = 0; /* End of string. */ 347 | while (num >= 10) { /* Conditional digits. */ 348 | buf[--width] = cast(char)((num%10) + '0'); 349 | num /= 10; 350 | } 351 | buf[--width] = cast(char)(num + '0'); // Always 1 digit. 352 | while (width != 0) /* Pad with blanks. */ 353 | buf[--width] = ' '; 354 | } 355 | 356 | /* 357 | * The argument "text" points to 358 | * a string. Append this line to the 359 | * buffer list buffer. Handcraft the EOL 360 | * on the end. Return TRUE if it worked and 361 | * FALSE if you ran out of room. 362 | */ 363 | int addline(string text) 364 | { 365 | LINE *lp; 366 | 367 | if ((lp=line_realloc(null, cast(int)text.length)) == null) 368 | return (FALSE); 369 | for (int i=0; i sbbuf.length) 207 | { 208 | sb = cast(CHAR_INFO *)alloca(numcols * CHAR_INFO.sizeof); 209 | } 210 | for (col = 0; col < numcols; col++) 211 | { 212 | auto c = buffer[col].chr; 213 | sb[col].UnicodeChar = cast(WCHAR)c; 214 | sb[col].Attributes = buffer[col].attr; 215 | if (c >= 0x10000) 216 | { 217 | /* Calculate surrogate pairs, but don't know yet how they 218 | * work, if at all, with WriteConsoleOutput() 219 | */ 220 | auto c0 = cast(wchar)((((c - 0x10000) >> 10) & 0x3FF) + 0xD800); 221 | auto c1 = cast(wchar)(((c - 0x10000) & 0x3FF) + 0xDC00); 222 | } 223 | //printf("col = %2d, x%2x, '%c'\n",col,sb[col].AsciiChar,sb[col].AsciiChar); 224 | } 225 | if (!WriteConsoleOutputW(cast(HANDLE)disp_state.handle,sb,sbsize,sbcoord,&sdrect)) 226 | { 227 | // error 228 | } 229 | physical[] = buffer[]; 230 | } 231 | 232 | /********************************* 233 | */ 234 | 235 | extern (C) int msm_init() 236 | { 237 | return GetSystemMetrics(SM_MOUSEPRESENT); 238 | } 239 | 240 | extern (C) 241 | { 242 | void msm_term() { } 243 | void msm_showcursor() { } 244 | void msm_hidecursor() { } 245 | } 246 | 247 | struct msm_status // current state of mouse 248 | { 249 | uint row; 250 | uint col; 251 | int buttons; 252 | } 253 | 254 | msm_status mstat; 255 | 256 | /************************* 257 | * Fold MOUSE_EVENT into mstat. 258 | */ 259 | 260 | static void mstat_update(MOUSE_EVENT_RECORD *pme) 261 | { 262 | mstat.row = pme.dwMousePosition.Y; 263 | mstat.col = pme.dwMousePosition.X; 264 | mstat.buttons = pme.dwButtonState & 3; 265 | } 266 | 267 | extern (C) int msm_getstatus(uint *pcol,uint *prow) 268 | { 269 | INPUT_RECORD buf; 270 | DWORD cNumRead; 271 | 272 | if (lookahead) 273 | { buf = lookaheadir; 274 | cNumRead = 1; 275 | } 276 | else if (!PeekConsoleInputA(hStdin,&buf,1,&cNumRead)) 277 | goto Lret; 278 | 279 | if (cNumRead) 280 | switch (buf.EventType) 281 | { 282 | case MOUSE_EVENT: 283 | mstat_update(&buf.MouseEvent); 284 | goto default; 285 | 286 | default: 287 | Ldiscard: 288 | if (lookahead) 289 | lookahead = 0; 290 | else 291 | ReadConsoleInputA(hStdin,&buf,1,&cNumRead); // discard 292 | break; 293 | 294 | case KEY_EVENT: 295 | if (mstat.buttons & 3) 296 | goto Ldiscard; 297 | break; 298 | } 299 | 300 | Lret: 301 | *prow = mstat.row; 302 | *pcol = mstat.col; 303 | return mstat.buttons; 304 | } 305 | 306 | /************************************* 307 | * Translate key from WIN32 to IBM PC style. 308 | * Params: 309 | * pkey = pointer to key data 310 | * Returns: 311 | * 0 if ignore it 312 | * References: 313 | * https://github.com/dlang/druntime/blob/master/src/core/sys/windows/wincon.d 314 | */ 315 | 316 | static uint win32_keytran(KEY_EVENT_RECORD *pkey) 317 | { 318 | if (!pkey.bKeyDown) 319 | return 0; // ignore button up events 320 | uint c = pkey.UnicodeChar; 321 | /+ 322 | printf("RepeatCount %x VirtualKeyCode %x VirtualScanCode %x UnicodeChar %x AsciiChar %x ControlKeyState %x\n", 323 | pkey.wRepeatCount, pkey.wVirtualKeyCode, pkey.wVirtualScanCode, pkey.UnicodeChar, pkey.AsciiChar, 324 | pkey.dwControlKeyState); 325 | +/ 326 | if (c == 0) 327 | { 328 | switch (pkey.wVirtualScanCode) 329 | { 330 | case 0x1D: // Ctrl 331 | case 0x38: // Alt 332 | case 0x2A: // Left Shift 333 | case 0x36: // Right Shift 334 | break; // ignore 335 | default: 336 | c = (pkey.wVirtualScanCode << 8) & 0xFF00; 337 | if (pkey.dwControlKeyState & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED)) 338 | { 339 | switch (c) 340 | { case 0x4700: c = 0x7700; break; // Home 341 | case 0x4F00: c = 0x7500; break; // End 342 | case 0x4900: c = 0x8400; break; // PgUp 343 | case 0x5100: c = 0x7600; break; // PgDn 344 | default: c = 0; break; 345 | } 346 | } 347 | break; 348 | } 349 | } 350 | else if (pkey.dwControlKeyState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED)) 351 | { 352 | c = (pkey.wVirtualScanCode << 8) & 0xFF00; 353 | } 354 | Lret: 355 | return c; 356 | } 357 | 358 | /************************** 359 | * Return when there are unread chars ready in the input. 360 | */ 361 | 362 | void ttwaitkeys() 363 | { 364 | } 365 | 366 | /************************************* 367 | * Wait for any input (yield to other processes). 368 | */ 369 | 370 | void ttyield() 371 | { 372 | if (!lookahead) 373 | { 374 | DWORD cNumRead; 375 | 376 | if (!ReadConsoleInputA(hStdin,&lookaheadir,1,&cNumRead)) 377 | { printf("readconsoleinput\n"); 378 | goto Lret; 379 | } 380 | } 381 | lookahead = 1; 382 | Lret: ; 383 | } 384 | 385 | /************************************* 386 | */ 387 | 388 | int ttkeysininput() 389 | { 390 | INPUT_RECORD buf; 391 | DWORD cNumRead; 392 | 393 | if (lookahead) 394 | { buf = lookaheadir; 395 | cNumRead = 1; 396 | } 397 | else if (!PeekConsoleInputA(hStdin,&buf,1,&cNumRead)) 398 | goto Lret; 399 | 400 | if (cNumRead) 401 | { 402 | switch (buf.EventType) 403 | { 404 | case MOUSE_EVENT: 405 | mstat_update(&buf.MouseEvent); 406 | goto default; 407 | 408 | default: 409 | Ldiscard: 410 | if (lookahead) 411 | lookahead = 0; 412 | else 413 | ReadConsoleInputA(hStdin,&buf,1,&cNumRead); // discard 414 | cNumRead = 0; 415 | break; 416 | 417 | case KEY_EVENT: 418 | if (!win32_keytran(&buf.KeyEvent)) 419 | goto Ldiscard; 420 | break; 421 | } 422 | } 423 | 424 | Lret: 425 | return cNumRead != 0; 426 | } 427 | 428 | extern (C) void popen() { assert(0); } 429 | 430 | void setClipboard(const(char)[] s) 431 | { 432 | if (OpenClipboard(null)) 433 | { 434 | EmptyClipboard(); 435 | 436 | HGLOBAL hmem = GlobalAlloc(GMEM_MOVEABLE, (s.length + 1) * char.sizeof); 437 | if (hmem) 438 | { 439 | auto p = cast(char*)GlobalLock(hmem); 440 | memcpy(p, s.ptr, s.length * char.sizeof); 441 | p[s.length] = 0; 442 | GlobalUnlock(hmem); 443 | 444 | SetClipboardData(CF_TEXT, hmem); 445 | } 446 | CloseClipboard(); 447 | } 448 | } 449 | 450 | char[] getClipboard() 451 | { 452 | char[] s = null; 453 | if (IsClipboardFormatAvailable(CF_TEXT) && 454 | OpenClipboard(null)) 455 | { 456 | HANDLE h = GetClipboardData(CF_TEXT); // CF_UNICODETEXT is UTF-16 457 | if (h) 458 | { 459 | auto p = cast(char*)GlobalLock(h); 460 | if (p) 461 | { 462 | size_t length = strlen(p); 463 | s = p[0 .. length].dup; 464 | } 465 | GlobalUnlock(h); 466 | } 467 | CloseClipboard(); 468 | } 469 | return s; 470 | } 471 | 472 | /*********************** 473 | * Open browser on help file. 474 | */ 475 | 476 | int help(bool f, int n) 477 | { 478 | printf("\nhelp \n"); 479 | char[MAX_PATH + 1] resolved_name = void; 480 | if (GetModuleFileNameA(NULL, resolved_name.ptr, MAX_PATH + 1)) 481 | { 482 | size_t len = strlen(resolved_name.ptr); 483 | size_t i; 484 | for (i = len; i; --i) 485 | { 486 | if (resolved_name[i] == '/' || 487 | resolved_name[i] == '\\' || 488 | resolved_name[i] == ':') 489 | { 490 | ++i; 491 | break; 492 | } 493 | } 494 | immutable(char)[7] doc = "me.html"; 495 | if (i + doc.sizeof <= MAX_PATH) 496 | { 497 | import std.process; 498 | memcpy(resolved_name.ptr + i, doc.ptr, doc.sizeof); 499 | printf("\nhelp2 '%.*s'\n", cast(int)(i + doc.sizeof), resolved_name.ptr); 500 | browse(cast(string)resolved_name[0 .. i + doc.sizeof]); 501 | } 502 | } 503 | return ed.FALSE; 504 | } 505 | 506 | } 507 | else 508 | { 509 | 510 | import ed; 511 | 512 | /*********************** 513 | * Open browser on help file. 514 | */ 515 | 516 | int help(bool f, int n) 517 | { 518 | return ed.FALSE; 519 | } 520 | 521 | } 522 | 523 | -------------------------------------------------------------------------------- /src/med/disp.d: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* This version of microEmacs is based on the public domain C 4 | * version written by Dave G. Conroy. 5 | * The D programming language version is written by Walter Bright. 6 | * http://www.digitalmars.com/d/ 7 | * This program is in the public domain. 8 | */ 9 | 10 | /* D interface to Digital Mars C/C++ disp package. 11 | * Windows only. 12 | * http://www.digitalmars.com/rtl/disp.html 13 | */ 14 | 15 | module disp; 16 | 17 | version (Windows) 18 | { 19 | 20 | extern (C) 21 | { 22 | 23 | struct disp_t 24 | { align(1): 25 | uint numrows; 26 | uint numcols; 27 | uint cursorrow; 28 | uint cursorcol; 29 | ubyte mono; 30 | ubyte snowycga; 31 | ubyte mode; 32 | ubyte inited; 33 | ubyte ega; 34 | ubyte[3] reserved; 35 | short nowrap; 36 | 37 | union 38 | { 39 | ushort *base; 40 | struct 41 | { uint offset; 42 | ushort basep; 43 | } 44 | } 45 | void *handle; 46 | } 47 | 48 | extern __gshared disp_t disp_state; 49 | 50 | int disp_printf(char *,...); 51 | int disp_getmode(); 52 | int disp_getattr(); 53 | int disp_putc(int); 54 | void disp_levelblockpoke(int,int,int,int,uint,uint *,uint,uint *,uint); 55 | void disp_open(); 56 | void disp_puts(const char *); 57 | void disp_box(int,int,uint,uint,uint,uint); 58 | void disp_close(); 59 | void disp_move(int,int); 60 | void disp_flush(); 61 | void disp_eeol(); 62 | void disp_eeop(); 63 | void disp_startstand(); 64 | void disp_endstand(); 65 | void disp_setattr(int); 66 | void disp_setcursortype(int); 67 | void disp_pokew(int,int,ushort); 68 | void disp_scroll(int,uint,uint,uint,uint,uint); 69 | void disp_setmode(ubyte); 70 | void disp_peekbox(ushort *,uint,uint,uint,uint); 71 | void disp_pokebox(ushort *,uint,uint,uint,uint); 72 | void disp_fillbox(uint,uint,uint,uint,uint); 73 | void disp_hidecursor(); 74 | void disp_showcursor(); 75 | ushort disp_peekw(int,int); 76 | 77 | enum 78 | { 79 | DISP_REVERSEVIDEO = 0x70, 80 | DISP_NORMAL = 0x07, 81 | DISP_UNDERLINE = 0x01, 82 | DISP_NONDISPLAY = 0x00, 83 | 84 | DISP_INTENSITY = 0x08, 85 | DISP_BLINK = 0x80, 86 | 87 | DISP_CURSORBLOCK = 100, 88 | DISP_CURSORHALF = 50, 89 | DISP_CURSORUL = 20, 90 | } 91 | 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /src/med/disprev.d: -------------------------------------------------------------------------------- 1 | 2 | immutable string VERSION = "3 Digital Mars"; 3 | immutable string EMACSREV = " med." ~ VERSION; 4 | -------------------------------------------------------------------------------- /src/med/ed.d: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* This version of microEmacs is based on the public domain C 4 | * version written by Dave G. Conroy. 5 | * The D programming language version is written by Walter Bright. 6 | * http://www.digitalmars.com/d/ 7 | * This program is in the public domain. 8 | */ 9 | 10 | 11 | /* 12 | * This file is the general header file for all parts of the MicroEMACS 13 | * display editor. It contains definitions used by everyone, and it contains 14 | * the stuff you have to edit to create a version of the editor for a specific 15 | * operating system and terminal. 16 | */ 17 | 18 | module ed; 19 | 20 | alias ubyte attr_t; 21 | 22 | struct attchar_t 23 | { 24 | dchar chr; 25 | attr_t attr; 26 | } 27 | 28 | enum 29 | { 30 | CVMVAS = 1, /* C-V, M-V arg. in screens. */ 31 | 32 | HUGE = 1000, /* Huge number */ 33 | 34 | AGRAVE = 0x60, /* M- prefix, Grave (LK201) */ 35 | METACH = 0x1B, /* M- prefix, Control-[, ESC */ 36 | CTMECH = 0x1C, /* C-M- prefix, Control-\ */ 37 | EXITCH = 0x1D, /* Exit level, Control-] */ 38 | CTRLCH = 0x1E, /* C- prefix, Control-^ */ 39 | HELPCH = 0x1F, /* Help key, Control-_ */ 40 | } 41 | 42 | enum MOUSEKEY = 0x12345678; // left mouse button down 43 | enum MOUSEKEYR = 0x12345679; // right mouse button down 44 | enum MOUSEKEYU = 0x7600; // right or left mouse button up 45 | 46 | 47 | enum 48 | { 49 | UPKEY = 0x4800, /* Up arrow key */ 50 | DNKEY = 0x5000, /* Down arrow key */ 51 | RTKEY = 0x4D00, /* Right arrow key */ 52 | LTKEY = 0x4B00, /* Left arrow key */ 53 | F1KEY = 0x3B00, 54 | F2KEY = 0x3C00, 55 | F3KEY = 0x3D00, 56 | F4KEY = 0x3E00, 57 | F5KEY = 0x3F00, 58 | F6KEY = 0x4000, 59 | F7KEY = 0x4100, 60 | F8KEY = 0x4200, 61 | F9KEY = 0x4300, 62 | F10KEY = 0x4400, 63 | F11KEY = 0x5700, 64 | F12KEY = 0x5800, 65 | AltF1KEY = 0x6800, 66 | AltF2KEY = 0x6900, 67 | AltF3KEY = 0x6A00, 68 | AltF4KEY = 0x6B00, 69 | AltF5KEY = 0x6C00, 70 | AltF6KEY = 0x6D00, 71 | AltF7KEY = 0x6E00, 72 | AltF8KEY = 0x6F00, 73 | AltF9KEY = 0x7000, 74 | AltF10KEY = 0x7100, 75 | ALTB = 0x3000, 76 | ALTC = 0x2E00, 77 | ALTD = 0x2000, 78 | ALTE = 0x1200, 79 | ALTF = 0x2100, 80 | ALTH = 0x2300, 81 | ALTM = 0x3200, 82 | ALTX = 0x2D00, 83 | ALTZ = 0x2C00, 84 | InsKEY = 0x5200, 85 | CtrlHome = 0x7700, 86 | CtrlEnd = 0x7500, 87 | DelKEY = 0x5300, 88 | CtrlRTKEY = 0x7400, 89 | CtrlLFKEY = 0x7300, 90 | HOMEKEY = 0x4700, 91 | ENDKEY = 0x4F00, 92 | PgUpKEY = 0x4900, 93 | PgDnKEY = 0x5100, 94 | 95 | GOLDKEY = ALTF, 96 | MENU_BUTTON = ALTH, 97 | } 98 | 99 | 100 | char CTRL(char c) { return c & 0x1F; } /* Control flag, or'ed in */ 101 | 102 | enum 103 | { 104 | META = METACH, /* Meta flag, or'ed in */ 105 | CTLX = CTRL('X'), /* ^X flag, or'ed in */ 106 | GOLD = GOLDKEY, /* Another Meta flag, or'ed in */ 107 | } 108 | 109 | enum 110 | { 111 | FALSE = 0, /* False, no, bad, etc. */ 112 | TRUE = 1, /* True, yes, good, etc. */ 113 | ABORT = 2, /* Death, ^G, abort, etc. */ 114 | } 115 | 116 | enum 117 | { 118 | CFCPCN = 0x0001, /* Last command was C-P, C-N */ 119 | CFKILL = 0x0002, /* Last command was a kill */ 120 | } 121 | 122 | /* 123 | * Seperate kbufp[] buffers for cut, word, line and char deletes... 124 | */ 125 | enum 126 | { DCUTBUF, 127 | DLINEBUF, 128 | DWORDBUF, 129 | DCHARBUF, 130 | DSPECBUF, /* maximum number of temp buffers */ 131 | } 132 | 133 | /* 134 | * State of the syntax highlighting 135 | */ 136 | enum Syntax 137 | { 138 | normal, 139 | keyword, 140 | string, 141 | comment, 142 | singleString, 143 | backtickString, 144 | } 145 | 146 | struct SyntaxState 147 | { 148 | Syntax syntax = Syntax.normal; 149 | int nest; // nest level for nested comments like /+ /+ +/ +/ 150 | } 151 | 152 | /******************************** 153 | * All configuration parameters are stored in this struct. 154 | */ 155 | 156 | struct CONFIG 157 | { 158 | attr_t modeattr; /* for mode line */ 159 | attr_t normattr; /* for normal text */ 160 | attr_t eolattr; /* for end of line */ 161 | attr_t markattr; /* for selected text */ 162 | char tabchar; /* char to use for tab display */ 163 | attr_t urlattr; // for URLs 164 | attr_t searchattr; // for search matches 165 | 166 | // for syntax highlighting 167 | attr_t keyword; 168 | attr_t string; 169 | attr_t comment; 170 | } 171 | 172 | enum Color : attr_t 173 | { 174 | // text colors 175 | black = 0, 176 | red = 1, 177 | green = 2, 178 | yellow = red | green, 179 | blue = 4, 180 | magenta = red | blue, // purple 181 | cyan = green | blue, 182 | lightGray = red | green | blue, 183 | 184 | darkGray = bold | black, 185 | lightRed = bold | red, 186 | lightGreen = bold | green, 187 | lightBlue = bold | blue, 188 | lightYellow = bold | yellow, 189 | lightMagenta = bold | magenta, 190 | lightCyan = bold | cyan, 191 | white = bold | lightGray, 192 | 193 | // background text colors 194 | bgBlack = black << 4, 195 | bgRed = red << 4, 196 | bgGreen = green << 4, 197 | bgYellow = yellow << 4, 198 | bgBlue = blue << 4, 199 | bgMagenta = magenta << 4, 200 | bgCyan = cyan << 4, 201 | bgGray = lightGray << 4, 202 | 203 | bgMask = 0x70, 204 | 205 | bold = 8, // bold only modifies text color by lightening it 206 | underline = 0x80, 207 | reverse = white, 208 | } 209 | 210 | 211 | /************** 212 | * George M. Jones {cbosgd,ihnp4}!osu-eddie!george 213 | * Work Phone: george@ohio-state.csnet 214 | * (614) 457-8600 CompuServe: 70003,2443 215 | */ 216 | 217 | -------------------------------------------------------------------------------- /src/med/file.d: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* This version of microEmacs is based on the public domain C 4 | * version written by Dave G. Conroy. 5 | * The D programming language version is written by Walter Bright. 6 | * http://www.digitalmars.com/d/ 7 | * This program is in the public domain. 8 | */ 9 | 10 | /* 11 | * The routines in this file 12 | * handle the reading and writing of 13 | * disk files. All of details about the 14 | * reading and writing of the disk are 15 | * in "fileio.c". 16 | */ 17 | 18 | module file; 19 | 20 | import core.stdc.stdlib; 21 | 22 | import std.stdio; 23 | import std.path; 24 | import std.string; 25 | import std.utf; 26 | import std.file; 27 | 28 | import ed; 29 | import main; 30 | import region; 31 | import window; 32 | import fileio; 33 | import line; 34 | import buffer; 35 | import display; 36 | import random; 37 | 38 | /********************************** 39 | * Save current file. Get next file and read it into the 40 | * current buffer. Next file is either: 41 | * o next argument from command line 42 | * o input from the user 43 | */ 44 | 45 | int filenext(bool f, int n) 46 | { int s; 47 | 48 | if (filesave(f,n) == FALSE) /* save current file */ 49 | return FALSE; 50 | if (gargi < gargs.length) /* if more files on command line */ 51 | { 52 | s = readin(gargs[gargi]); 53 | gargi++; 54 | } 55 | else /* get file name from user */ 56 | s = fileread(f,n); 57 | curbp.b_bname = makename(curbp.b_fname); 58 | return s; 59 | } 60 | 61 | /********************************** 62 | * Insert a file into the current buffer. 63 | */ 64 | 65 | int Dinsertfile(bool f, int n) 66 | { 67 | string fnamed; 68 | 69 | if (mlreply("Insert file: ", null, fnamed) == FALSE) 70 | return FALSE; 71 | 72 | string fname = toUTF8(fnamed); 73 | try 74 | { 75 | fname = std.path.expandTilde(fname); 76 | auto fp = File(fname); 77 | mlwrite("[Reading file]"); 78 | int nline = 0; 79 | char[] line; 80 | size_t s; 81 | while ((s = fp.readln(line)) != 0) 82 | { 83 | foreach(char c; line) 84 | { 85 | if (c == '\r' || c == '\n') 86 | break; 87 | if (line_insert(1,c) == FALSE) 88 | return FALSE; 89 | } 90 | if (random_newline(FALSE,1) == FALSE) 91 | return FALSE; 92 | ++nline; 93 | } 94 | fp.close(); 95 | if (nline == 1) 96 | mlwrite("[Read 1 line]"); 97 | else 98 | mlwrite("[Read %d lines]", nline); 99 | return TRUE; 100 | } 101 | catch (Exception e) 102 | { 103 | mlwrite(e.toString()); 104 | return FALSE; 105 | } 106 | finally 107 | { 108 | foreach (wp; windows) 109 | { 110 | if (wp.w_bufp == curbp) { 111 | wp.w_flag |= WFMODE|WFHARD; 112 | } 113 | } 114 | } 115 | } 116 | 117 | /* 118 | * Read a file into the current 119 | * buffer. This is really easy; all you do it 120 | * find the name of the file, and call the standard 121 | * "read a file into the current buffer" code. 122 | * Bound to "C-X C-R". 123 | */ 124 | int fileread(bool f, int n) 125 | { 126 | int s; 127 | string fname; 128 | 129 | if ((s=mlreply("Read file: ", null, fname)) != TRUE) 130 | return (s); 131 | return (readin(fname)); 132 | } 133 | 134 | /* 135 | * Select a file for editing. 136 | * Look around to see if you can find the 137 | * file in another buffer; if you can find it 138 | * just switch to the buffer. If you cannot find 139 | * the file, create a new buffer, read in the 140 | * text, and switch to the new buffer. 141 | * Bound to GOLD E. 142 | */ 143 | int filevisit(bool f, int n) 144 | { 145 | string fname; 146 | 147 | return mlreply("Visit file: ", null, fname) && 148 | window_split(f,n) && 149 | file_readin(fname); 150 | } 151 | 152 | int file_readin(string fname) 153 | { 154 | LINE *lp; 155 | int i; 156 | int s; 157 | string bname; 158 | 159 | /* If there is an existing buffer with the same file name, simply */ 160 | /* switch to it instead of reading the file again. */ 161 | foreach (bp; buffers) 162 | { 163 | /* Always redo temporary buffers, check for filename match. */ 164 | if ((bp.b_flag&BFTEMP)==0 && globMatch(bp.b_fname, fname)) 165 | { 166 | /* If the current buffer now becomes undisplayed */ 167 | if (--curbp.b_nwnd == 0) 168 | { 169 | curbp.b_dotp = curwp.w_dotp; 170 | curbp.b_doto = curwp.w_doto; 171 | curbp.b_markp = curwp.w_markp; 172 | curbp.b_marko = curwp.w_marko; 173 | } 174 | curbp = bp; 175 | curwp.w_bufp = bp; 176 | if (bp.b_nwnd++ == 0) /* if buffer not already displayed */ 177 | { 178 | curwp.w_dotp = bp.b_dotp; 179 | curwp.w_doto = bp.b_doto; 180 | curwp.w_markp = bp.b_markp; 181 | curwp.w_marko = bp.b_marko; 182 | } 183 | else 184 | { 185 | /* Set dot to be at place where other window has it */ 186 | foreach (wp; windows) 187 | { 188 | if (wp!=curwp && wp.w_bufp==bp) 189 | { 190 | curwp.w_dotp = wp.w_dotp; 191 | curwp.w_doto = wp.w_doto; 192 | curwp.w_markp = wp.w_markp; 193 | curwp.w_marko = wp.w_marko; 194 | break; 195 | } 196 | } 197 | } 198 | 199 | /* Adjust frame so dot is at center */ 200 | lp = curwp.w_dotp; 201 | i = curwp.w_ntrows/2; 202 | while (i-- && lback(lp)!=curbp.b_linep) 203 | lp = lback(lp); 204 | curwp.w_linep = lp; 205 | 206 | curwp.w_flag |= WFMODE|WFHARD; 207 | mlwrite("[Old buffer]"); 208 | return TRUE; 209 | } 210 | } 211 | 212 | bname = makename(fname); /* New buffer name. */ 213 | BUFFER* bp; 214 | while ((bp=buffer_find(bname, FALSE, 0)) != null) 215 | { 216 | s = mlreply("Buffer name: ", null, bname); 217 | if (s == ABORT) /* ^G to just quit */ 218 | return (s); 219 | if (s == FALSE) { /* CR to clobber it */ 220 | bname = makename(fname); 221 | break; 222 | } 223 | } 224 | if (bp==null && (bp=buffer_find(bname, TRUE, 0))==null) 225 | { mlwrite("Cannot create buffer"); 226 | return (FALSE); 227 | } 228 | if (--curbp.b_nwnd == 0) /* Undisplay */ 229 | { curbp.b_dotp = curwp.w_dotp; 230 | curbp.b_doto = curwp.w_doto; 231 | curbp.b_markp = curwp.w_markp; 232 | curbp.b_marko = curwp.w_marko; 233 | } 234 | curbp = bp; /* Switch to it. */ 235 | curwp.w_bufp = bp; 236 | curbp.b_nwnd++; 237 | return (readin(fname)); /* Read it in. */ 238 | } 239 | 240 | /* 241 | * Read file "fname" into the current 242 | * buffer, blowing away any text found there. Called 243 | * by both the read and visit commands. Return the final 244 | * status of the read. Also called by the mainline, 245 | * to read in a file specified on the command line as 246 | * an argument. 247 | */ 248 | int readin(string dfname) 249 | { 250 | auto bp = curbp; // Cheap. 251 | auto b = buffer_clear(bp); // Might be old. 252 | if (b != TRUE) 253 | return b; 254 | bp.b_flag &= ~(BFTEMP|BFCHG); 255 | bp.setFilename(dfname); 256 | 257 | /* Determine if file is read-only */ 258 | auto fname = std.path.expandTilde(toUTF8(dfname)); 259 | if (ffreadonly(fname)) /* is file read-only? */ 260 | bp.b_flag |= BFRDONLY; 261 | else 262 | bp.b_flag &= ~BFRDONLY; 263 | 264 | try 265 | { 266 | if (!std.file.exists(fname)) 267 | { 268 | mlwrite("[New file]"); 269 | return TRUE; 270 | } 271 | auto fp = File(fname); 272 | mlwrite("[Reading file]"); 273 | int nline = 0; 274 | char[] line; 275 | size_t s; 276 | bool first = true; 277 | while ((s = fp.readln(line)) != 0) 278 | { 279 | if (line.length && line[$ - 1] == '\n') 280 | line = line[0 .. $ - 1]; 281 | if (line.length && line[$ - 1] == '\r') 282 | line = line[0 .. $ - 1]; 283 | 284 | LINE *lp1; 285 | LINE *lp2; 286 | 287 | if ((lp1=line_realloc(null,0)) == null) { 288 | s = FIOERR; /* Keep message on the */ 289 | break; /* display. */ 290 | } 291 | lp2 = lback(curbp.b_linep); 292 | lp2.l_fp = lp1; 293 | lp1.l_fp = curbp.b_linep; 294 | lp1.l_bp = lp2; 295 | curbp.b_linep.l_bp = lp1; 296 | if (first && line.length >= 3 && line[0] == 0xEF && line[1] == 0xBB && line[2] == 0xBF) 297 | line = line[3..$]; // skip BOM 298 | lp1.l_text = line[].dup; 299 | 300 | first = false; 301 | ++nline; 302 | } 303 | fp.close(); 304 | if (nline == 1) 305 | mlwrite("[Read 1 line]"); 306 | else 307 | mlwrite("[Read %d lines]", nline); 308 | return TRUE; 309 | } 310 | catch (Exception e) 311 | { 312 | mlwrite(e.toString()); 313 | return FALSE; 314 | } 315 | finally 316 | { 317 | foreach (wp; windows) 318 | { 319 | if (wp.w_bufp == curbp) { 320 | wp.w_linep = lforw(curbp.b_linep); 321 | wp.w_dotp = lforw(curbp.b_linep); 322 | wp.w_doto = 0; 323 | wp.w_markp = null; 324 | wp.w_marko = 0; 325 | wp.w_flag |= WFMODE|WFHARD; 326 | } 327 | } 328 | } 329 | } 330 | 331 | /* 332 | * Take a file name, and from it 333 | * fabricate a buffer name. This routine knows 334 | * about the syntax of file names on the target system. 335 | * I suppose that this information could be put in 336 | * a better place than a line of code. 337 | */ 338 | string makename(string fname) 339 | { 340 | return fname; 341 | } 342 | 343 | /* 344 | * Ask for a file name, and write the 345 | * contents of the current buffer or region to that file. 346 | * Update the remembered file name and clear the 347 | * buffer changed flag. This handling of file names 348 | * is different from the earlier versions, and 349 | * is more compatible with Gosling EMACS than 350 | * with ITS EMACS. Bound to "C-X C-W". 351 | */ 352 | int filewrite(bool f, int n) 353 | { 354 | int s; 355 | string fname; 356 | 357 | if ((s=mlreply("Write file: ", null, fname)) != TRUE) 358 | return (s); 359 | if (curwp.w_markp) /* if marking a region */ 360 | { REGION region; 361 | 362 | if (!getregion(®ion)) 363 | return FALSE; 364 | return file_writeregion(fname,®ion); 365 | } 366 | else 367 | { 368 | if ((s=writeout(fname)) == TRUE) { 369 | curbp.setFilename(fname); 370 | fileunmodify(f,n); 371 | } 372 | } 373 | return (s); 374 | } 375 | 376 | /**************************** 377 | * Mark a file as being unmodified. 378 | */ 379 | 380 | int fileunmodify(bool f, int n) 381 | { 382 | curbp.b_flag &= ~BFCHG; 383 | 384 | /* Update mode lines. */ 385 | foreach (wp; windows) 386 | { 387 | if (wp.w_bufp == curbp) 388 | wp.w_flag |= WFMODE; 389 | } 390 | return TRUE; 391 | } 392 | 393 | /* 394 | * Save the contents of the current 395 | * buffer in its associated file. No nothing 396 | * if nothing has changed (this may be a bug, not a 397 | * feature). Error if there is no remembered file 398 | * name for the buffer. Bound to "C-X C-S". May 399 | * get called by "C-Z". 400 | */ 401 | int filesave(bool f, int n) 402 | { 403 | WINDOW *wp; 404 | int s; 405 | 406 | if ((curbp.b_flag&BFCHG) == 0) /* Return, no changes. */ 407 | return (TRUE); 408 | if (curbp.b_fname.length == 0) { /* Must have a name. */ 409 | mlwrite("No file name"); 410 | return (FALSE); 411 | } 412 | if ((s=writeout(curbp.b_fname)) == TRUE) { 413 | fileunmodify(f,n); 414 | } 415 | return (s); 416 | } 417 | 418 | /* 419 | * Save the contents of each and every modified 420 | * buffer. Does nothing if the buffer is temporary 421 | * or has no filename. 422 | */ 423 | int filemodify(bool f, int n) 424 | { 425 | int s = TRUE; 426 | 427 | auto oldbp = curbp; 428 | foreach (bp; buffers) 429 | { 430 | curbp = bp; 431 | if((curbp.b_flag&BFCHG) == 0 || /* if no changes */ 432 | curbp.b_flag & BFTEMP || /* if temporary */ 433 | curbp.b_fname.length == 0) /* Must have a name */ 434 | continue; 435 | if((s&=writeout(curbp.b_fname)) == TRUE ) 436 | fileunmodify(f,n); 437 | } 438 | curbp = oldbp; 439 | return( s ); 440 | } 441 | 442 | /* 443 | * This function performs the details of file 444 | * writing. Uses the file management routines in the 445 | * "fileio.c" package. The number of lines written is 446 | * displayed. Sadly, it looks inside a LINE; provide 447 | * a macro for this. Most of the grief is error 448 | * checking of some sort. 449 | */ 450 | int writeout(string dfn) 451 | { 452 | auto fn = std.path.expandTilde(toUTF8(dfn)); 453 | /* 454 | * Supply backups when writing files. 455 | */ 456 | version (Windows) 457 | { 458 | auto backupname = std.path.setExtension(fn, "bak"); 459 | } 460 | else 461 | { 462 | auto backupname = buildPath(dirName(fn), baseName(fn) ~ "~"); 463 | } 464 | 465 | try 466 | { 467 | std.file.remove(backupname); // Remove old backup file 468 | } 469 | catch (Throwable o) 470 | { 471 | } 472 | 473 | if (ffrename(fn, backupname) != FIOSUC) 474 | return FALSE; // Make new backup file 475 | 476 | try 477 | { 478 | auto f = File(fn, "w"); 479 | 480 | if ( ffchmod( fn, backupname ) != FIOSUC ) /* Set protection */ 481 | { f.close(); 482 | return( FALSE ); 483 | } 484 | 485 | auto lp = lforw(curbp.b_linep); // First line. 486 | int nline = 0; // Number of lines. 487 | while (lp != curbp.b_linep) { 488 | f.writeln(toUTF8(lp.l_text[0 .. llength(lp)])); 489 | ++nline; 490 | lp = lforw(lp); 491 | } 492 | 493 | f.close(); 494 | if (nline == 1) 495 | mlwrite("[Wrote 1 line]"); 496 | else 497 | mlwrite("[Wrote %d lines]", nline); 498 | return TRUE; 499 | } 500 | catch (Exception e) 501 | { 502 | mlwrite(e.toString()); 503 | return FALSE; 504 | } 505 | } 506 | 507 | /* 508 | * The command allows the user 509 | * to modify the file name associated with 510 | * the current buffer. It is like the "f" command 511 | * in UNIX "ed". The operation is simple; just zap 512 | * the name in the BUFFER structure, and mark the windows 513 | * as needing an update. You can type a blank line at the 514 | * prompt if you wish. 515 | */ 516 | int filename(bool f, int n) 517 | { 518 | int s; 519 | string fname; 520 | 521 | if ((s=mlreply("New File Name: ", null, fname)) == ABORT) 522 | return (s); 523 | curbp.setFilename( s == FALSE ? null : fname); 524 | foreach (wp; windows) 525 | { // Update mode lines. 526 | if (wp.w_bufp == curbp) 527 | wp.w_flag |= WFMODE; 528 | } 529 | return (TRUE); 530 | } 531 | 532 | /******************************* 533 | * Write region out to file. 534 | */ 535 | 536 | int file_writeregion(string dfilename, REGION* region) 537 | { 538 | auto lp = region.r_linep; /* First line. */ 539 | auto loffs = region.r_offset; 540 | auto size = region.r_size; 541 | int nline = 0; /* Number of lines. */ 542 | 543 | try 544 | { 545 | auto filename = std.path.expandTilde(toUTF8(dfilename)); 546 | auto f = File(filename, "w"); 547 | while (size > 0) 548 | { 549 | auto nchars = llength(lp) - loffs; 550 | if (nchars > size) /* if last line is not a full line */ 551 | nchars = size; 552 | f.writeln(toUTF8(lp.l_text[loffs .. loffs + nchars])); 553 | size -= nchars + 1; 554 | ++nline; 555 | lp = lforw(lp); 556 | loffs = 0; 557 | } 558 | f.close(); 559 | if (nline == 1) 560 | mlwrite("[Wrote 1 line]"); 561 | else 562 | mlwrite("[Wrote %d lines]", nline); 563 | return TRUE; 564 | } 565 | catch (Exception e) 566 | { 567 | mlwrite(e.toString()); 568 | return FALSE; 569 | } 570 | } 571 | 572 | -------------------------------------------------------------------------------- /src/med/fileio.d: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* This version of microEmacs is based on the public domain C 4 | * version written by Dave G. Conroy. 5 | * The D programming language version is written by Walter Bright. 6 | * http://www.digitalmars.com/d/ 7 | * This program is in the public domain. 8 | */ 9 | 10 | /* 11 | * The routines in this file read and write ASCII files from the disk. All of 12 | * the knowledge about files are here. A better message writing scheme should 13 | * be used. 14 | */ 15 | 16 | module fileio; 17 | 18 | import core.stdc.stdio; 19 | import core.stdc.stdlib; 20 | import core.stdc.errno; 21 | 22 | import std.file; 23 | import std.path; 24 | import std.string; 25 | import std.stdio; 26 | import std.conv; 27 | 28 | version (Windows) 29 | { 30 | import core.sys.windows.windows; 31 | } 32 | 33 | version (Posix) 34 | { 35 | import core.sys.posix.unistd; 36 | import core.sys.posix.sys.stat; 37 | } 38 | 39 | import ed; 40 | import display; 41 | 42 | enum ENOENT = 2; 43 | 44 | enum 45 | { 46 | FIOSUC = 0, /* File I/O, success. */ 47 | FIOFNF = 1, /* File I/O, file not found. */ 48 | FIOEOF = 2, /* File I/O, end of file. */ 49 | FIOERR = 3, /* File I/O, error. */ 50 | } 51 | 52 | /*************************** 53 | * Determine if file is read-only. 54 | */ 55 | 56 | bool ffreadonly(string name) 57 | { 58 | uint a; 59 | bool exists = true; 60 | try 61 | { 62 | a = std.file.getAttributes(name); 63 | } 64 | catch (Throwable o) 65 | { 66 | exists = false; 67 | } 68 | 69 | version (Win32) 70 | { 71 | return (a & FILE_ATTRIBUTE_READONLY) != 0; 72 | } 73 | else 74 | { 75 | return exists && (a & S_IWUSR) == 0; 76 | } 77 | } 78 | 79 | /* 80 | * Rename a file 81 | */ 82 | int ffrename(string from, string to) 83 | { 84 | try 85 | { 86 | from = std.path.expandTilde(from); 87 | to = std.path.expandTilde(to); 88 | version (Posix) 89 | { 90 | stat_t buf; 91 | if( stat( toStringz(from), &buf ) != -1 92 | && !(buf.st_uid == getuid() && (buf.st_mode & octal!200)) 93 | && !(buf.st_gid == getgid() && (buf.st_mode & octal!20)) 94 | && !( (buf.st_mode & octal!2)) ) 95 | { 96 | mlwrite("Cannot open file for writing."); 97 | /* Note the above message is a lie, but because this */ 98 | /* routine is only called by the backup file creation */ 99 | /* code, the message will look right to the user. */ 100 | return( FIOERR ); 101 | } 102 | } 103 | rename( from, to ); 104 | } 105 | catch (Throwable o) 106 | { 107 | } 108 | return( FIOSUC ); 109 | } 110 | 111 | 112 | /* 113 | * Change the protection on a file to match that on file 114 | */ 115 | int ffchmod(string subject, string image) 116 | { 117 | version (Posix) 118 | { 119 | subject = std.path.expandTilde(subject); 120 | image = std.path.expandTilde(image); 121 | 122 | uint attr; 123 | try 124 | { 125 | attr = std.file.getAttributes(image); 126 | } 127 | catch (FileException fe) 128 | { 129 | return( FIOSUC ); 130 | /* Note that this won't work in all cases, but because */ 131 | /* this is only called from the backup file creator, it */ 132 | /* will work. UGLY!! */ 133 | } 134 | if (chmod( toStringz(subject), attr ) == -1 ) 135 | { 136 | mlwrite("Cannot open file for writing."); 137 | /* Note the above message is a lie, but because this */ 138 | /* routine is only called by the backup file creation */ 139 | /* code, the message will look right to the user. */ 140 | return( FIOERR ); 141 | } 142 | } 143 | return( FIOSUC ); 144 | } 145 | 146 | -------------------------------------------------------------------------------- /src/med/more.d: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* This version of microEmacs is based on the public domain C 4 | * version written by Dave G. Conroy. 5 | * The D programming language version is written by Walter Bright. 6 | * http://www.digitalmars.com/d/ 7 | * This program is in the public domain. 8 | */ 9 | 10 | 11 | /* 12 | * Due to my (Bjorn Benson) laziness, the functions will all 13 | * work with a positive argument, but may or may not with 14 | * a negative. 15 | */ 16 | 17 | module more; 18 | 19 | import core.stdc.stdio; 20 | 21 | import std.ascii; 22 | import std.uni; 23 | import std.process; 24 | 25 | import ed; 26 | import main; 27 | import window; 28 | import buffer; 29 | import line; 30 | import search; 31 | import random; 32 | import region; 33 | import word; 34 | import basic; 35 | import terminal; 36 | import display; 37 | import url; 38 | import utf; 39 | 40 | version (Posix) 41 | { 42 | import core.sys.posix.signal; 43 | import core.sys.posix.unistd; 44 | } 45 | 46 | /* 47 | * The multiple delete buffers 48 | */ 49 | enum 50 | { 51 | DK_CUT, 52 | DK_LINE, 53 | DK_WORD, 54 | DK_CHAR, 55 | } 56 | 57 | void SETMARK() 58 | { 59 | curwp.w_markp = curwp.w_dotp; 60 | curwp.w_marko = curwp.w_doto; 61 | } 62 | 63 | /* 64 | * Current direction that things happen in 65 | */ 66 | enum 67 | { 68 | ADVANCE, 69 | BACKUP, 70 | } 71 | 72 | int Dcur_direction = ADVANCE; 73 | 74 | int Dsearch(bool f, int n) 75 | { 76 | if( Dcur_direction == ADVANCE ) 77 | return( forwsearch(f, n) ); 78 | else return( backsearch(f, n) ); 79 | } 80 | 81 | int Dsearchagain(bool f, int n) 82 | { 83 | int s; 84 | Dnoask_search = true; 85 | scope(exit) Dnoask_search = false; 86 | if( Dcur_direction == ADVANCE ) 87 | s = forwsearch(f, n); 88 | else s = backsearch(f, n); 89 | return s; 90 | } 91 | 92 | int Ddelline(bool f, int n) 93 | { 94 | int s = true; 95 | 96 | kill_setbuffer(DK_LINE); 97 | kill_freebuffer(); 98 | while( n-- > 0 && s ) 99 | { curwp.w_doto = 0; 100 | s &= line_delete(llength(curwp.w_dotp) + 1, true); 101 | } 102 | kill_setbuffer(DK_CUT); 103 | return s; 104 | } 105 | 106 | int Dundelline(bool f, int n) 107 | { 108 | int s = true; 109 | 110 | kill_setbuffer(DK_LINE); 111 | while( n-- > 0 && s ) 112 | { 113 | curwp.w_doto = 0; 114 | s = random_yank(true, 1); 115 | backline(false, 1); 116 | curwp.w_doto = 0; 117 | } 118 | kill_setbuffer(DK_CUT); 119 | return s; 120 | } 121 | 122 | int Ddelword(bool f, int n) 123 | { 124 | int s = true; 125 | 126 | kill_setbuffer(DK_WORD); 127 | kill_freebuffer(); 128 | while( n-- > 0 && s ) 129 | { 130 | SETMARK(); 131 | s = word_forw(false, 1); 132 | if( !s ) break; 133 | s = region_kill(false, 1); 134 | } 135 | kill_setbuffer(DK_CUT); 136 | return s; 137 | } 138 | 139 | int Ddelbword(bool f, int n) 140 | { 141 | int s = true; 142 | 143 | kill_setbuffer(DK_WORD); 144 | kill_freebuffer(); 145 | while( n-- > 0 && s ) 146 | { 147 | SETMARK; 148 | s = word_back(false, 1); 149 | if( !s ) break; 150 | s = region_kill(false, 1); 151 | } 152 | kill_setbuffer(DK_CUT); 153 | return s; 154 | } 155 | 156 | int Dundelword(bool f, int n) 157 | { 158 | int s = true; 159 | 160 | kill_setbuffer(DK_WORD); 161 | while( n-- > 0 && s ) 162 | s &= random_yank(true, 1); 163 | kill_setbuffer(DK_CUT); 164 | return s; 165 | } 166 | 167 | int Dadvance(bool f, int n) 168 | { 169 | Dcur_direction = ADVANCE; 170 | return true; 171 | } 172 | 173 | int Dbackup(bool f, int n) 174 | { 175 | Dcur_direction = BACKUP; 176 | return true; 177 | } 178 | 179 | int Dignore(bool f, int n) 180 | { 181 | /* Ignore this command. Useful for ^S and ^Q flow control */ 182 | /* sent out by some terminals. */ 183 | return true; 184 | } 185 | 186 | int Dpause(bool f, int n) 187 | { 188 | version (Posix) 189 | { 190 | term.t_move( term.t_nrow - 1, 0 ); 191 | term.t_eeop(); 192 | term.t_flush(); 193 | term.t_close(); 194 | killpg(getpgid(0), 18); /* SIGTSTP -- stop the current program */ 195 | term.t_open(); 196 | sgarbf = true; 197 | window_refresh(false, 1); 198 | } 199 | return true; 200 | } 201 | 202 | /********************************* 203 | * Decide whether to uppercase a word or a region. 204 | */ 205 | 206 | int misc_upper(bool f, int n) 207 | { 208 | if (curwp.w_markp) 209 | return region_upper(f,n); 210 | else 211 | return word_upper(f,n); 212 | } 213 | 214 | /********************************* 215 | * Decide whether to lowercase a word or a region. 216 | */ 217 | 218 | int misc_lower(bool f, int n) 219 | { 220 | if (curwp.w_markp) 221 | return region_lower(f,n); 222 | else 223 | return word_lower(f,n); 224 | } 225 | 226 | /********************************* 227 | * Insert file name and date at top of file. 228 | */ 229 | 230 | int Dinsertdate(bool f, int n) 231 | { return false; 232 | } 233 | 234 | /*********************************** 235 | * Remove trailing whitespace from line. 236 | */ 237 | 238 | void deblank() 239 | { int len; 240 | int n; 241 | int c; 242 | int i; 243 | 244 | len = llength(curwp.w_dotp); 245 | for (i = len - 1; i >= 0; i--) 246 | { 247 | c = lgetc(curwp.w_dotp, i); 248 | if (!isSpace(c)) 249 | break; 250 | } 251 | n = (len - 1) - i; 252 | if (n) 253 | { 254 | curwp.w_doto = i + 1; 255 | line_delete(n,false); 256 | } 257 | } 258 | 259 | /********************************* 260 | * Convert C comment to C++ comment. 261 | */ 262 | 263 | int Dcppcomment(bool f, int n) 264 | { 265 | int c; 266 | int i; 267 | LINE *dotpsave; 268 | int dotosave; 269 | 270 | if (n < 0) 271 | goto err; 272 | if (window_marking(curwp)) 273 | { REGION region; 274 | int s; 275 | 276 | if ((s = getregion(®ion)) != true) 277 | return s; 278 | dotpsave = curwp.w_dotp; 279 | dotosave = curwp.w_doto; 280 | curwp.w_dotp = region.r_linep; 281 | curwp.w_doto = region.r_offset; 282 | n = region.r_nlines; 283 | } 284 | while (n--) 285 | { int len; 286 | 287 | deblank(); 288 | len = llength(curwp.w_dotp); 289 | if (len) 290 | { 291 | for (i = 0; i + 3 < len; i++) 292 | { 293 | c = lgetc(curwp.w_dotp, i); 294 | if (c == '/' && lgetc(curwp.w_dotp, i + 1) == '*') 295 | { 296 | if (lgetc(curwp.w_dotp, len - 2) == '*' && 297 | lgetc(curwp.w_dotp, len - 1) == '/') 298 | { 299 | curwp.w_doto = i + 1; 300 | line_delete(1,false); 301 | line_insert(1,'/'); 302 | curwp.w_doto = len - 2; 303 | line_delete(2,false); 304 | deblank(); 305 | break; 306 | } 307 | } 308 | } 309 | curwp.w_doto = 0; /* move to beginning of line */ 310 | } 311 | if (forwline(false,1) == false) 312 | goto err; 313 | } 314 | if (window_marking(curwp)) 315 | { 316 | if (dotosave > llength(dotpsave)) 317 | dotosave = llength(dotpsave); 318 | curwp.w_dotp = dotpsave; 319 | curwp.w_doto = dotosave; 320 | } 321 | return true; 322 | 323 | err: 324 | return false; 325 | } 326 | 327 | /************************************ 328 | * Open browser on URL. 329 | */ 330 | int openBrowser(bool f, int n) 331 | { 332 | LINE* dotp = curwp.w_dotp; 333 | auto s = getURL(dotp.l_text[0 .. llength(dotp)], curwp.w_doto); 334 | if (s) 335 | { 336 | browse(cast(string)s); 337 | return TRUE; 338 | } 339 | return FALSE; 340 | } 341 | 342 | /*************************** 343 | * Look up current character in the replacement table, 344 | * and replace it with the next character in the table. 345 | * Returns: 346 | * TRUE = success 347 | * FALSE = failure 348 | */ 349 | 350 | int scrollUnicode(bool f, int n) 351 | { 352 | /* Mapping table of one character to the next in each entry 353 | */ 354 | __gshared immutable string[] table = 355 | [ 356 | "a\ä\à\á\â\ã\å\æ\α\ª", 357 | "e\è\é\ê\ë\ε\η", 358 | "i\ì\í\î\ï\ι", 359 | "o\ò\ó\ô\õ\ö\ø\ο\œ", 360 | "u\ù\ú\û\ü\μ\υ", 361 | 362 | "A\À\Á\Â\Ã\Ä\Å\Æ\Α\∀", 363 | "E\È\É\Ê\Ë\Ε\∃\∈\∉\∋", 364 | "I\Ì\Í\Î\Ï\Ι\∫", 365 | "O\Ò\Ó\Ô\Ö\Ο", 366 | "U\Ù\Ú\Û\Ü\∩\∪\⊂\⊃\⊄", 367 | 368 | "c\ç\©", 369 | "C\Ç", 370 | 371 | "$\€\¢\£\¤\¥", 372 | "\"\“\”\„\«\»", 373 | "'\‘\’\‚\´", 374 | "-\–\—\¯\‾\−", 375 | "~\˜\∼\≅\≈", 376 | "!\¡", 377 | ]; 378 | 379 | LINE* dotp = curwp.w_dotp; 380 | auto s = dotp.l_text[0 .. llength(dotp)]; 381 | size_t index = curwp.w_doto; 382 | 383 | size_t i = index; 384 | dchar dc = decodeUTF8(s, i); 385 | foreach (entry; table) 386 | { 387 | for (size_t j = 0; j < entry.length; ) 388 | { 389 | dchar dr = decodeUTF8(entry, j); 390 | if (dr == dc) 391 | { 392 | if (j == entry.length) 393 | j = 0; 394 | size_t k = j; 395 | decodeUTF8(entry, k); 396 | 397 | /* Replace s[index .. i] with entry[j .. k] 398 | */ 399 | line_delete(cast(int)(i - index), FALSE); 400 | foreach (char c; entry[j .. k]) 401 | line_insert(1, c); 402 | backchar(f, cast(int)(k - j)); 403 | line_change(WFEDIT); 404 | 405 | return TRUE; 406 | } 407 | } 408 | } 409 | return FALSE; 410 | } 411 | -------------------------------------------------------------------------------- /src/med/mouse.d: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* This version of microEmacs is based on the public domain C 4 | * version written by Dave G. Conroy. 5 | * The D programming language version is written by Walter Bright. 6 | * http://www.digitalmars.com/d/ 7 | * This program is in the public domain. 8 | */ 9 | 10 | 11 | module mouse; 12 | 13 | import disp; 14 | import core.stdc.time; 15 | 16 | import ed; 17 | import window; 18 | import line; 19 | import main; 20 | import terminal; 21 | import display; 22 | import word; 23 | 24 | //#include 25 | 26 | static int clicks = 0; /* number of clicks we've seen */ 27 | static clock_t lastclick; /* time of last click */ 28 | 29 | /********************************* 30 | * Call this routine in the main command loop. 31 | * It handles any mouse commands. 32 | * Returns: 33 | * 0 no mouse input 34 | * !=0 value is a keystroke 35 | */ 36 | 37 | int mouse_command() 38 | { uint x,y; 39 | WINDOW *wp; 40 | LINE *lp; 41 | int status; 42 | 43 | if (!hasmouse) /* if no mouse installed */ 44 | return 0; 45 | status = msm_getstatus(&x,&y); /* read button status */ 46 | mouse_tocursor(&x,&y); /* collect real cursor coords */ 47 | if (status & 1) /* if left button is down */ 48 | { int doto; 49 | 50 | mouse_findpos(x,y,&wp,&lp,&doto); 51 | if (wp && lp) 52 | { markcol = wp.w_startcol + x; 53 | mouse_markdrag(wp,lp,doto); 54 | } 55 | else 56 | { if (wp) 57 | { 58 | curbp = wp.w_bufp; 59 | curwp = wp; 60 | /* Examine window action buttons */ 61 | switch (x) 62 | { case 0: 63 | window_only(FALSE,1); 64 | goto L2; 65 | case 1: 66 | window_split(FALSE,1); 67 | goto L2; 68 | case 2: 69 | delwind(FALSE,1); 70 | L2: update(); 71 | goto L1; 72 | case 3: 73 | do 74 | { window_mvup(FALSE,1); 75 | update(); 76 | } while (mouse_leftisdown()); 77 | break; 78 | case 4: 79 | do 80 | { window_mvdn(FALSE,1); 81 | update(); 82 | } while (mouse_leftisdown()); 83 | break; 84 | default: 85 | mouse_windrag(wp); 86 | break; 87 | } 88 | update(); 89 | } 90 | else 91 | L1: 92 | while (mouse_leftisdown()) /* wait till button goes up */ 93 | { } 94 | clicks = 0; 95 | } 96 | } 97 | else if (status & 2) /* if right button is down */ 98 | { 99 | //return memenu_mouse(y,x); 100 | } 101 | return 0; 102 | } 103 | 104 | /******************************* 105 | * Convert from Microsoft coordinates to proper cursor coordinates. 106 | */ 107 | 108 | static void mouse_tocursor(uint* px, uint* py) 109 | { 110 | } 111 | 112 | /*************************** 113 | * Set cursor at row,col. 114 | */ 115 | 116 | static void mouse_findpos(uint col, uint row, WINDOW** p_wp, LINE** p_lp, int* p_doto) 117 | { int r; 118 | int i; 119 | LINE *lp; 120 | 121 | *p_wp = null; 122 | *p_lp = null; 123 | *p_doto = 0; /* default cases */ 124 | r = 0; /* starting row for window */ 125 | foreach (wp; windows) 126 | { 127 | if (row <= r + wp.w_ntrows) 128 | { 129 | *p_wp = wp; 130 | if (row == r + wp.w_ntrows) 131 | return; 132 | for (lp = wp.w_linep; lp != wp.w_bufp.b_linep; lp = lforw(lp)) 133 | { if (row == r) 134 | break; 135 | r++; 136 | } 137 | *p_lp = lp; 138 | /* Determine offset into line corresponding to col */ 139 | *p_doto = coltodoto(lp,wp.w_startcol + col); 140 | return; 141 | } 142 | r += wp.w_ntrows + 1; 143 | } 144 | } 145 | 146 | /***************************** 147 | * Given an initial position, drag the mouse, marking 148 | * text as we go. 149 | */ 150 | 151 | static void mouse_markdrag(WINDOW* wp, LINE* lp, int doto) 152 | { uint x,y; 153 | 154 | curbp = wp.w_bufp; 155 | curwp = wp; 156 | if (lp != wp.w_dotp) /* if on different line */ 157 | { wp.w_dotp = lp; 158 | wp.w_flag |= WFMOVE; 159 | } 160 | wp.w_doto = doto; 161 | wp.w_markp = lp; 162 | wp.w_marko = doto; /* set new mark */ 163 | curwp.w_flag |= WFHARD; 164 | update(); 165 | 166 | /* Continue marking until button goes up */ 167 | while (msm_getstatus(&x,&y) & 1) 168 | { 169 | mouse_tocursor(&x,&y); /* collect real cursor coords */ 170 | mouse_findpos(x,y,&wp,&lp,&doto); 171 | if (wp && wp == curwp && lp) 172 | { 173 | if (wp.w_markp || lp != wp.w_dotp) /* if on different line */ 174 | { 175 | wp.w_dotp = lp; 176 | wp.w_flag |= WFMOVE; 177 | } 178 | wp.w_doto = doto; 179 | } 180 | else if (!wp || 181 | wp != curwp && wp.w_toprow > curwp.w_toprow || 182 | wp == curwp && !lp) 183 | window_mvdn(FALSE,1); 184 | else 185 | window_mvup(FALSE,1); 186 | curgoal = curwp.w_startcol + x; 187 | lastflag |= CFCPCN; /* behave as if forwline() or backline() */ 188 | update(); 189 | } 190 | /* If mark start and mark end match, then no mark */ 191 | if (wp.w_markp == wp.w_dotp && 192 | wp.w_marko == wp.w_doto) 193 | { clock_t thisclick; 194 | 195 | wp.w_markp = null; 196 | thisclick = clock(); 197 | if (clicks) 198 | { if (thisclick - lastclick > 500) //CLOCKS_PER_SEC / 2) 199 | clicks = 0; 200 | } 201 | clicks++; 202 | lastclick = thisclick; 203 | 204 | switch (clicks) 205 | { case 1: 206 | break; 207 | case 2: 208 | word_select(FALSE,1); 209 | goto L1; 210 | case 3: 211 | word_lineselect(FALSE,1); 212 | L1: 213 | mlerase(); 214 | update(); 215 | break; 216 | default: 217 | clicks = 0; 218 | break; 219 | } 220 | } 221 | else 222 | clicks = 0; 223 | } 224 | 225 | /***************************** 226 | * Given an initial position, drag the border of the window around. 227 | */ 228 | 229 | static void mouse_windrag(WINDOW* wp) 230 | { uint x,y; 231 | LINE *lp; 232 | int doto; 233 | 234 | /* Continue dragging window until button goes up */ 235 | while (msm_getstatus(&x,&y) & 1) 236 | { 237 | mouse_tocursor(&x,&y); /* collect real cursor coords */ 238 | mouse_findpos(x,y,&wp,&lp,&doto); 239 | if (wp && wp == curwp && lp || 240 | wp != curwp && wp && wp.w_toprow < curwp.w_toprow) 241 | window_shrink(FALSE,1); 242 | else if (!wp || 243 | wp != curwp && wp.w_toprow > curwp.w_toprow) 244 | window_enlarge(FALSE,1); 245 | update(); 246 | } 247 | } 248 | 249 | /***************************** 250 | * Return !=0 if left button is down. 251 | */ 252 | 253 | static int mouse_leftisdown() 254 | { uint x,y; 255 | 256 | return msm_getstatus(&x,&y) & 1; 257 | } 258 | -------------------------------------------------------------------------------- /src/med/region.d: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* This version of microEmacs is based on the public domain C 4 | * version written by Dave G. Conroy. 5 | * The D programming language version is written by Walter Bright. 6 | * http://www.digitalmars.com/d/ 7 | * This program is in the public domain. 8 | */ 9 | 10 | /* 11 | * The routines in this file 12 | * deal with the region, that magic space 13 | * between "." and mark. Some functions are 14 | * commands. Some functions are just for 15 | * internal use. 16 | */ 17 | 18 | module region; 19 | 20 | import std.string; 21 | import std.ascii; 22 | 23 | import ed; 24 | import line; 25 | import main; 26 | import window; 27 | import display; 28 | import buffer; 29 | 30 | /* 31 | * The starting position of a region, and the size of the region in 32 | * characters, is kept in a region structure. Used by the region commands. 33 | */ 34 | struct REGION { 35 | LINE *r_linep; /* Origin LINE address */ 36 | uint r_offset; /* Origin LINE offset (not in col mode) */ 37 | uint r_size; /* Length in characters (approx in col mode) */ 38 | uint r_nlines; /* Number of lines */ 39 | uint r_leftcol; /* Left column for column cut */ 40 | uint r_rightcol; /* And right column */ 41 | } 42 | 43 | 44 | /********************************* 45 | * Toggle column cut/paste mode. 46 | */ 47 | 48 | int region_togglemode(bool f, int n) 49 | { 50 | column_mode ^= 1; /* toggle screen mode */ 51 | line_change(WFHARD); 52 | mlwrite(column_mode ? "[Column mode on]" : "[Column mode off]"); 53 | return TRUE; 54 | } 55 | 56 | /* 57 | * Kill the region. Ask "getregion" 58 | * to figure out the bounds of the region. 59 | * Move "." to the start, and kill the characters. 60 | */ 61 | int region_kill(bool f, int n) 62 | { 63 | int s; 64 | REGION region; 65 | 66 | if (curbp.b_flag & BFRDONLY) 67 | return FALSE; 68 | if ((s=getregion(®ion)) != TRUE) 69 | goto err; 70 | if (region.r_size == 0) 71 | goto err; /* error if 0 length */ 72 | if ((lastflag&CFKILL) == 0) /* This is a kill type */ 73 | kill_freebuffer(); /* command, so do magic */ 74 | thisflag |= CFKILL; /* kill buffer stuff. */ 75 | curwp.w_dotp = region.r_linep; 76 | curwp.w_doto = region.r_offset; 77 | curwp.w_markp = null; 78 | if (column_mode) 79 | { 80 | if (!kill_setsize(region.r_size)) 81 | return FALSE; 82 | while (region.r_nlines--) 83 | { int lright; 84 | LINE* linep = curwp.w_dotp; 85 | 86 | curwp.w_doto = coltodoto(linep,region.r_leftcol); 87 | lright = coltodoto(linep,region.r_rightcol); 88 | if (!line_delete(lright - curwp.w_doto, TRUE)) 89 | goto err; 90 | if (!kill_appendchar('\n')) 91 | goto err; 92 | curwp.w_dotp = lforw(linep); 93 | } 94 | curwp.w_dotp = region.r_linep; 95 | curwp.w_doto = coltodoto(region.r_linep,region.r_leftcol); 96 | line_change(WFHARD); 97 | } 98 | else 99 | s = line_delete(region.r_size, TRUE); 100 | kill_toClipboard(); 101 | return s; 102 | err: 103 | return FALSE; 104 | } 105 | 106 | /* 107 | * Copy all of the characters in the 108 | * region to the kill buffer. Don't move dot 109 | * at all. This is a bit like a kill region followed 110 | * by a yank. Bound to "M-W". 111 | */ 112 | int region_copy(bool f, int n) 113 | { 114 | LINE* linep; 115 | int loffs; 116 | int s; 117 | REGION region; 118 | 119 | if ((s=getregion(®ion)) != TRUE) 120 | return (s); 121 | if ((lastflag&CFKILL) == 0) /* Kill type command. */ 122 | kill_freebuffer(); 123 | 124 | /* Turn off marked region */ 125 | curwp.w_markp = null; 126 | curwp.w_flag |= WFHARD; 127 | 128 | thisflag |= CFKILL; 129 | linep = region.r_linep; /* Current line. */ 130 | loffs = region.r_offset; /* Current offset. */ 131 | if (!kill_setsize(region.r_size)) 132 | return FALSE; 133 | if (column_mode) 134 | { 135 | while (region.r_nlines--) 136 | { int lright; 137 | int lleft; 138 | 139 | lleft = coltodoto(linep,region.r_leftcol); 140 | lright = coltodoto(linep,region.r_rightcol); 141 | if (!kill_appendstring(linep.l_text[lleft .. lright])) 142 | goto err; 143 | if (!kill_appendchar('\n')) 144 | goto err; 145 | linep = lforw(linep); 146 | } 147 | } 148 | else 149 | while (region.r_size) { 150 | if (loffs == llength(linep)) { /* End of line. */ 151 | if (kill_appendchar('\n') != TRUE) 152 | return FALSE; 153 | linep = lforw(linep); 154 | loffs = 0; 155 | region.r_size--; 156 | } else { /* Middle of line. */ 157 | int i; 158 | 159 | i = llength(linep) - loffs; 160 | if (i > region.r_size) 161 | i = region.r_size; 162 | if (kill_appendstring(linep.l_text[loffs .. loffs + i]) != TRUE) 163 | return FALSE; 164 | loffs += i; 165 | region.r_size -= i; 166 | } 167 | } 168 | kill_toClipboard(); 169 | return (TRUE); 170 | 171 | err: return FALSE; 172 | } 173 | 174 | /* 175 | * Upper/lower case region. Zap all of the upper 176 | * case characters in the region to lower case. Use 177 | * the region code to set the limits. Scan the buffer, 178 | * doing the changes. Call "line_change" to ensure that 179 | * redisplay is done in all buffers. 180 | */ 181 | int region_lower(bool f, int n) 182 | { 183 | return region_case(TRUE); 184 | } 185 | 186 | int region_upper(bool f, int n) 187 | { 188 | return region_case(FALSE); 189 | } 190 | 191 | private int region_case(bool flag) 192 | { 193 | LINE* linep; 194 | int loffs; 195 | int c; 196 | int s; 197 | REGION region; 198 | 199 | if ((s=getregion(®ion)) != TRUE) 200 | return (s); 201 | line_change(WFHARD); 202 | /*curwp.w_markp = null;*/ 203 | linep = region.r_linep; 204 | if (column_mode) 205 | { 206 | while (region.r_nlines--) 207 | { int lright; 208 | 209 | loffs = coltodoto(linep,region.r_leftcol); 210 | lright = coltodoto(linep,region.r_rightcol); 211 | for (; loffs < lright; loffs++) 212 | { c = lgetc(linep, loffs); 213 | if (flag ? isUpper(c) : isLower(c)) 214 | lputc(linep, loffs, cast(char)(c ^ 0x20)); 215 | } 216 | linep = lforw(linep); 217 | } 218 | } 219 | else 220 | { 221 | loffs = region.r_offset; 222 | while (region.r_size--) { 223 | if (loffs == llength(linep)) { 224 | linep = lforw(linep); 225 | loffs = 0; 226 | } else { 227 | c = lgetc(linep, loffs); 228 | if (flag ? isUpper(c) : isLower(c)) 229 | lputc(linep, loffs, cast(char)(c ^ 0x20)); 230 | ++loffs; 231 | } 232 | } 233 | } 234 | return (TRUE); 235 | } 236 | 237 | /* 238 | * This routine figures out the 239 | * bounds of the region in the current window, and 240 | * fills in the fields of the "REGION" structure pointed 241 | * to by "rp". Because the dot and mark are usually very 242 | * close together, we scan outward from dot looking for 243 | * mark. This should save time. Return a standard code. 244 | * Callers of this routine should be prepared to get 245 | * an "ABORT" status; we might make this have the 246 | * conform thing later. 247 | */ 248 | int getregion(REGION* rp) 249 | { 250 | LINE *flp; 251 | LINE *blp; 252 | int nlines; /* number of lines in region */ 253 | int fsize; 254 | int bsize; 255 | int size; 256 | 257 | if (!window_marking(curwp)) { 258 | mlwrite("No mark set in this window"); 259 | return (FALSE); 260 | } 261 | 262 | /* Figure out left and right columns, this is valid only if */ 263 | /* column cut mode is on. */ 264 | if (markcol < curgoal) 265 | { rp.r_leftcol = markcol; 266 | rp.r_rightcol = curgoal; 267 | } 268 | else 269 | { rp.r_leftcol = curgoal; 270 | rp.r_rightcol = markcol; 271 | } 272 | 273 | rp.r_nlines = 1; /* always at least 1 line */ 274 | 275 | /* If region lies within one line */ 276 | if (curwp.w_dotp == curwp.w_markp) 277 | { rp.r_linep = curwp.w_dotp; 278 | if (column_mode) 279 | { 280 | rp.r_size = rp.r_rightcol - rp.r_leftcol; 281 | } 282 | else 283 | { 284 | if (curwp.w_doto < curwp.w_marko) 285 | { rp.r_offset = curwp.w_doto; 286 | rp.r_size = curwp.w_marko-curwp.w_doto; 287 | } 288 | else 289 | { rp.r_offset = curwp.w_marko; 290 | rp.r_size = curwp.w_doto-curwp.w_marko; 291 | } 292 | } 293 | return (TRUE); 294 | } 295 | 296 | blp = curwp.w_dotp; 297 | bsize = curwp.w_doto; 298 | flp = curwp.w_dotp; 299 | fsize = llength(flp)-curwp.w_doto+1; 300 | while (flp!=curbp.b_linep || lback(blp)!=curbp.b_linep) 301 | { 302 | rp.r_nlines++; 303 | if (flp != curbp.b_linep) { 304 | flp = lforw(flp); 305 | if (flp == curwp.w_markp) { 306 | rp.r_linep = curwp.w_dotp; 307 | rp.r_offset = curwp.w_doto; 308 | size = fsize+curwp.w_marko; 309 | /* Don't count last line if it's at start */ 310 | if (curwp.w_marko == 0) 311 | rp.r_nlines--; 312 | goto done; 313 | } 314 | fsize += llength(flp)+1; 315 | } 316 | if (lback(blp) != curbp.b_linep) { 317 | blp = lback(blp); 318 | bsize += llength(blp)+1; 319 | if (blp == curwp.w_markp) { 320 | rp.r_linep = blp; 321 | rp.r_offset = curwp.w_marko; 322 | size = bsize - curwp.w_marko; 323 | /* Don't count last line if it's at start */ 324 | if (curwp.w_doto == 0) 325 | rp.r_nlines--; 326 | goto done; 327 | } 328 | } 329 | } 330 | mlwrite("Bug: lost mark"); 331 | return (FALSE); 332 | 333 | done: 334 | if (column_mode) 335 | size = (rp.r_rightcol - rp.r_leftcol + 1) * rp.r_nlines; 336 | rp.r_size = size; 337 | return TRUE; 338 | } 339 | -------------------------------------------------------------------------------- /src/med/spawn.d: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* This version of microEmacs is based on the public domain C 4 | * version written by Dave G. Conroy. 5 | * The D programming language version is written by Walter Bright. 6 | * http://www.digitalmars.com/d/ 7 | * This program is in the public domain. 8 | */ 9 | 10 | 11 | /* 12 | * The routines in this file are called to create a subjob running a command 13 | * interpreter. 14 | */ 15 | 16 | module spawn; 17 | 18 | import core.stdc.stdlib; 19 | import core.stdc.time; 20 | 21 | import std.conv; 22 | import std.stdio; 23 | import std.file; 24 | import std.process; 25 | import std.string; 26 | import std.utf; 27 | 28 | version(Posix) 29 | { 30 | import core.sys.posix.unistd; 31 | } 32 | 33 | import ed; 34 | import buffer; 35 | import window; 36 | import display; 37 | import main; 38 | import file; 39 | import terminal; 40 | 41 | 42 | 43 | /* 44 | * Create a subjob with a copy of the command intrepreter in it. When the 45 | * command interpreter exits, mark the screen as garbage so that you do a full 46 | * repaint. Bound to "C-C". The message at the start in VMS puts out a newline. 47 | * Under some (unknown) condition, you don't get one free when DCL starts up. 48 | */ 49 | int spawncli(bool f, int n) 50 | { 51 | movecursor(term.t_nrow-1, 0); /* Seek to last line. */ 52 | version (Windows) 53 | { 54 | term.t_flush(); 55 | auto comspec = core.stdc.stdlib.getenv("COMSPEC"); 56 | string[] args; 57 | args ~= to!string(comspec); 58 | args ~= "COMMAND.COM"; 59 | spawnProcess(args); 60 | } 61 | version (Posix) 62 | { 63 | term.t_flush(); 64 | term.t_close(); /* stty to old settings */ 65 | auto cp = core.stdc.stdlib.getenv("SHELL"); 66 | if (cp && *cp != '\0') 67 | core.stdc.stdlib.system(cp); 68 | else 69 | core.stdc.stdlib.system("exec /bin/sh"); 70 | sleep(2); 71 | term.t_open(); 72 | } 73 | sgarbf = TRUE; 74 | return(TRUE); 75 | } 76 | 77 | /* 78 | * Run a one-liner in a subjob. When the command returns, wait for a single 79 | * character to be typed, then mark the screen as garbage so a full repaint is 80 | * done. Bound to "C-X !". 81 | */ 82 | int spawn(bool f, int n) 83 | { 84 | int s; 85 | string line; 86 | version (Windows) 87 | { 88 | if ((s=mlreply("MS-DOS command: ", null, line)) != TRUE) 89 | return (s); 90 | core.stdc.stdlib.system(toUTF8(line).toStringz()); 91 | while (term.t_getchar() != '\r') /* Pause. */ 92 | { 93 | } 94 | sgarbf = TRUE; 95 | return (TRUE); 96 | } 97 | version (Posix) 98 | { 99 | if ((s=mlreply("! ", null, line)) != TRUE) 100 | return (s); 101 | term.t_putchar('\n'); /* Already have '\r' */ 102 | term.t_flush(); 103 | term.t_close(); /* stty to old modes */ 104 | core.stdc.stdlib.system(toUTF8(line).toStringz()); 105 | sleep(2); 106 | term.t_open(); 107 | printf("[End]"); /* Pause. */ 108 | term.t_flush(); 109 | while ((s = term.t_getchar()) != '\r' && s != ' ') 110 | { 111 | } 112 | sgarbf = TRUE; 113 | return (TRUE); 114 | } 115 | } 116 | 117 | /* 118 | * Pipe a one line command into a window 119 | * Bound to ^X @ 120 | */ 121 | int spawn_pipe(bool f, int n) 122 | { 123 | int s; /* return status from CLI */ 124 | WINDOW *wp; /* pointer to new window */ 125 | BUFFER *bp; /* pointer to buffer to zot */ 126 | static string bname = "[DOS]"; 127 | 128 | static string filnam = "DOS.TMP"; 129 | string line; /* command line sent to shell */ 130 | string sline; 131 | 132 | /* get the command to pipe in */ 133 | if ((s = mlreply("DOS:", null, line)) != TRUE) 134 | return s; 135 | 136 | /* get rid of the command output buffer if it exists */ 137 | if ((bp=buffer_find(bname, FALSE, BFTEMP)) != null) /* if buffer exists */ 138 | { 139 | /* If buffer is displayed, try to move it off screen */ 140 | /* (can't remove an on-screen buffer) */ 141 | if (bp.b_nwnd) /* if buffer is displayed */ 142 | { if (bp == curbp) /* if it's the current window */ 143 | window_next(FALSE,1); /* make another window current */ 144 | window_only(FALSE, 1); 145 | 146 | if (buffer_remove(bp) != TRUE) 147 | goto fail; 148 | } 149 | } 150 | 151 | /* split the current window to make room for the command output */ 152 | if (window_split(FALSE, 1) == FALSE) 153 | goto fail; 154 | 155 | sline = toUTF8(line) ~ ">" ~ filnam; 156 | 157 | version (Windows) 158 | { 159 | movecursor(term.t_nrow - 2, 0); 160 | core.stdc.stdlib.system(sline.toStringz()); 161 | sgarbf = TRUE; 162 | if (std.file.exists(filnam) && std.file.isFile(filnam)) 163 | return FALSE; 164 | } 165 | version (Posix) 166 | { 167 | term.t_putchar('\n'); /* Already have '\r' */ 168 | term.t_flush(); 169 | term.t_close(); /* stty to old modes */ 170 | core.stdc.stdlib.system(sline.toStringz()); 171 | term.t_open(); 172 | term.t_flush(); 173 | sgarbf = TRUE; 174 | } 175 | 176 | /* and read the stuff in */ 177 | if (file_readin(filnam) == FALSE) 178 | return(FALSE); 179 | 180 | /* and get rid of the temporary file */ 181 | remove(filnam); 182 | return(TRUE); 183 | 184 | fail: 185 | return FALSE; 186 | } 187 | 188 | /* 189 | * filter a buffer through an external DOS program 190 | * Bound to ^X # 191 | */ 192 | int spawn_filter(bool f, int n) 193 | { 194 | int s; /* return status from CLI */ 195 | BUFFER *bp; /* pointer to buffer to zot */ 196 | string line; /* command line to send to shell */ 197 | string tmpnam; /* place to store real file name */ 198 | string bname1 = "fltinp"; 199 | 200 | string filnam1 = "fltinp"; 201 | string filnam2 = "fltout"; 202 | 203 | if (curbp.b_flag & BFRDONLY) /* if buffer is read-only */ 204 | return FALSE; /* fail */ 205 | 206 | /* get the filter name and its args */ 207 | if ((s=mlreply("Filter:", null, line)) != TRUE) 208 | return(s); 209 | 210 | /* setup the proper file names */ 211 | bp = curbp; 212 | tmpnam = bp.b_fname; /* save the original name */ 213 | bp.b_fname = bname1; /* set it to our new one */ 214 | 215 | /* write it out, checking for errors */ 216 | if (writeout(filnam1) != TRUE) { 217 | mlwrite("[Cannot write filter file]"); 218 | bp.b_fname = tmpnam; 219 | return(FALSE); 220 | } 221 | 222 | line ~= " fltout"; 223 | version (Windows) 224 | { 225 | movecursor(term.t_nrow - 2, 0); 226 | core.stdc.stdlib.system(toUTF8(line).toStringz()); 227 | } 228 | version (Posix) 229 | { 230 | term.t_putchar('\n'); /* Already have '\r' */ 231 | term.t_flush(); 232 | term.t_close(); /* stty to old modes */ 233 | core.stdc.stdlib.system(toUTF8(line).toStringz()); 234 | term.t_open(); 235 | term.t_flush(); 236 | } 237 | 238 | sgarbf = TRUE; 239 | s = TRUE; 240 | 241 | /* on failure, escape gracefully */ 242 | if (s != TRUE || ((s = readin(filnam2)) == FALSE)) { 243 | mlwrite("[Execution failed]"); 244 | bp.b_fname = tmpnam; 245 | goto ret; 246 | } 247 | 248 | /* reset file name */ 249 | bp.b_fname = tmpnam; /* restore name */ 250 | bp.b_flag |= BFCHG; /* flag it as changed */ 251 | s = TRUE; 252 | 253 | ret: 254 | /* and get rid of the temporary file */ 255 | remove(toUTF8(filnam1)); 256 | remove(toUTF8(filnam2)); 257 | return s; 258 | } 259 | 260 | 261 | -------------------------------------------------------------------------------- /src/med/syntaxc.d: -------------------------------------------------------------------------------- 1 | 2 | /* This version of microEmacs is based on the public domain C 3 | * version written by Dave G. Conroy. 4 | * The D programming language version is written by Walter Bright. 5 | * http://www.digitalmars.com/d/ 6 | * This program is in the public domain. 7 | */ 8 | 9 | /* This is the C syntax highligher. 10 | */ 11 | 12 | module syntaxc; 13 | 14 | import core.stdc.stdio; 15 | import core.stdc.ctype; 16 | 17 | import std.utf; 18 | 19 | import ed; 20 | import buffer; 21 | import window; 22 | import main; 23 | import display; 24 | import random; 25 | 26 | /******************************** 27 | * Returns: 28 | * starting syntax state of next line 29 | */ 30 | SyntaxState syntaxHighlightC(SyntaxState syntaxState, const(char)[] text, attr_t[] attr) 31 | { 32 | size_t i = 0; 33 | 34 | switch (syntaxState.syntax) 35 | { 36 | case Syntax.string: 37 | case Syntax.singleString: 38 | { 39 | const quote = (syntaxState.syntax == Syntax.string) ? '"' : 40 | '\''; 41 | const istart = i; 42 | bool escape; 43 | while (i < text.length) 44 | { 45 | if (text[i] == quote && !escape) 46 | { 47 | ++i; 48 | attr[istart .. i] = config.string; 49 | goto Loop; 50 | } 51 | else if (text[i] == '\\') 52 | escape ^= true; 53 | else 54 | escape = false; 55 | ++i; 56 | } 57 | attr[istart .. i] = config.string; 58 | return SyntaxState(syntaxState.syntax); 59 | } 60 | 61 | case Syntax.comment: 62 | { 63 | // it's /* */ comment 64 | const istart = i; 65 | while (i < text.length) 66 | { 67 | if (text[i] == '*' && i + 1 < text.length && text[i + 1] == '/') 68 | { 69 | i += 2; 70 | attr[istart .. i] = config.comment; 71 | goto Loop; 72 | } 73 | ++i; 74 | } 75 | attr[istart .. i] = config.comment; 76 | return SyntaxState(Syntax.comment); 77 | } 78 | 79 | default: 80 | break; 81 | } 82 | 83 | Loop: 84 | while (i < text.length) 85 | { 86 | const c = text[i]; 87 | switch (c) 88 | { 89 | case 'a': .. case 'z': 90 | case 'A': .. case 'Z': 91 | case '_': 92 | Idstart: 93 | { 94 | const istart = i; 95 | ++i; 96 | while (i < text.length) 97 | { 98 | const ci = text[i]; 99 | if (isalnum(ci) || ci == '_' || ci & 0x80) 100 | { 101 | ++i; 102 | continue; 103 | } 104 | break; 105 | } 106 | const id = text[istart .. i]; 107 | attr[istart .. i] = isCKeyword(id) ? config.keyword : config.normattr; 108 | continue; 109 | } 110 | 111 | case '/': 112 | { 113 | const istart = i; 114 | ++i; 115 | if (i < text.length) 116 | { 117 | if (text[i] == '/') 118 | { 119 | attr[istart .. text.length] = config.comment; 120 | return SyntaxState(Syntax.normal); 121 | } 122 | 123 | if (text[i] == '*') 124 | { 125 | ++i; 126 | while (i < text.length) 127 | { 128 | if (text[i] == '*' && i + 1 < text.length && text[i + 1] == '/') 129 | { 130 | i += 2; 131 | attr[istart .. i] = config.comment; 132 | continue Loop; 133 | } 134 | ++i; 135 | } 136 | attr[istart .. i] = config.comment; 137 | return SyntaxState(Syntax.comment); 138 | } 139 | } 140 | continue; 141 | } 142 | 143 | case '"': 144 | case '\'': 145 | { 146 | const istart = i; 147 | bool escape; 148 | ++i; 149 | while (i < text.length) 150 | { 151 | if (text[i] == c && !escape) 152 | { 153 | ++i; 154 | attr[istart .. i] = config.string; 155 | continue Loop; 156 | } 157 | else if (text[i] == '\\') 158 | escape ^= true; 159 | else 160 | escape = false; 161 | ++i; 162 | } 163 | attr[istart .. i] = config.string; 164 | return SyntaxState(c == '"' ? Syntax.string : 165 | Syntax.singleString); 166 | } 167 | 168 | default: 169 | if (text[i] & 0x80) 170 | goto Idstart; 171 | attr[i] = config.normattr; 172 | ++i; 173 | continue; 174 | } 175 | /* 176 | switch (syntaxState.syntax) 177 | { 178 | case Syntax.normal: 179 | break; 180 | 181 | case Syntax.string: 182 | case Syntax.singleString: 183 | break; 184 | 185 | case Syntax.comment: 186 | break; 187 | 188 | default: 189 | assert(0); 190 | } 191 | */ 192 | } 193 | return SyntaxState(Syntax.normal); 194 | } 195 | 196 | private bool isCKeyword(const(char)[] s) 197 | { 198 | switch (s) 199 | { 200 | case "break": 201 | case "inline": 202 | case "void": 203 | case "case": 204 | case "if": 205 | case "int": 206 | case "volatile": 207 | case "char": 208 | case "long": 209 | case "while ": 210 | case "const": 211 | case "register": 212 | case "continue": 213 | case "restrict": 214 | case "default": 215 | case "return": 216 | case "do": 217 | case "short": 218 | case "double": 219 | case "signed": 220 | case "else": 221 | case "sizeof": 222 | case "enum": 223 | case "static": 224 | case "extern": 225 | case "struct": 226 | case "float": 227 | case "switch": 228 | case "for": 229 | case "typedef": 230 | case "goto": 231 | case "union ": 232 | case "_Alignas ": 233 | case "_Alignof ": 234 | case "_Atomic ": 235 | case "_Bool ": 236 | case "_Complex ": 237 | case "_Generic ": 238 | case "_Imaginary ": 239 | case "_Noreturn ": 240 | case "_Static_assert ": 241 | case "_Thread_local ": 242 | case "__FILE__": 243 | case "__LINE__": 244 | return true; 245 | 246 | default: 247 | return false; 248 | } 249 | } 250 | -------------------------------------------------------------------------------- /src/med/syntaxcpp.d: -------------------------------------------------------------------------------- 1 | 2 | /* This version of microEmacs is based on the public domain C 3 | * version written by Dave G. Conroy. 4 | * The D programming language version is written by Walter Bright. 5 | * http://www.digitalmars.com/d/ 6 | * This program is in the public domain. 7 | */ 8 | 9 | /* This is the C++ syntax highligher. 10 | */ 11 | 12 | module syntaxcpp; 13 | 14 | import core.stdc.stdio; 15 | import core.stdc.ctype; 16 | 17 | import std.utf; 18 | 19 | import ed; 20 | import buffer; 21 | import window; 22 | import main; 23 | import display; 24 | import random; 25 | 26 | /******************************** 27 | * Returns: 28 | * starting syntax state of next line 29 | */ 30 | SyntaxState syntaxHighlightCPP(SyntaxState syntaxState, const(char)[] text, attr_t[] attr) 31 | { 32 | size_t i = 0; 33 | 34 | switch (syntaxState.syntax) 35 | { 36 | case Syntax.string: 37 | case Syntax.singleString: 38 | { 39 | const quote = (syntaxState.syntax == Syntax.string) ? '"' : 40 | '\''; 41 | const istart = i; 42 | bool escape; 43 | while (i < text.length) 44 | { 45 | if (text[i] == quote && !escape) 46 | { 47 | ++i; 48 | attr[istart .. i] = config.string; 49 | goto Loop; 50 | } 51 | else if (text[i] == '\\') 52 | escape ^= true; 53 | else 54 | escape = false; 55 | ++i; 56 | } 57 | attr[istart .. i] = config.string; 58 | return SyntaxState(syntaxState.syntax); 59 | } 60 | 61 | case Syntax.comment: 62 | { 63 | // it's /* */ comment 64 | const istart = i; 65 | while (i < text.length) 66 | { 67 | if (text[i] == '*' && i + 1 < text.length && text[i + 1] == '/') 68 | { 69 | i += 2; 70 | attr[istart .. i] = config.comment; 71 | goto Loop; 72 | } 73 | ++i; 74 | } 75 | attr[istart .. i] = config.comment; 76 | return SyntaxState(Syntax.comment); 77 | } 78 | 79 | default: 80 | break; 81 | } 82 | 83 | Loop: 84 | while (i < text.length) 85 | { 86 | const c = text[i]; 87 | switch (c) 88 | { 89 | case 'a': .. case 'z': 90 | case 'A': .. case 'Z': 91 | case '_': 92 | Idstart: 93 | { 94 | const istart = i; 95 | ++i; 96 | while (i < text.length) 97 | { 98 | const ci = text[i]; 99 | if (isalnum(ci) || ci == '_' || ci & 0x80) 100 | { 101 | ++i; 102 | continue; 103 | } 104 | break; 105 | } 106 | const id = text[istart .. i]; 107 | attr[istart .. i] = isCPPKeyword(id) ? config.keyword : config.normattr; 108 | continue; 109 | } 110 | 111 | case '/': 112 | { 113 | const istart = i; 114 | ++i; 115 | if (i < text.length) 116 | { 117 | if (text[i] == '/') 118 | { 119 | attr[istart .. text.length] = config.comment; 120 | return SyntaxState(Syntax.normal); 121 | } 122 | 123 | if (text[i] == '*') 124 | { 125 | ++i; 126 | while (i < text.length) 127 | { 128 | if (text[i] == '*' && i + 1 < text.length && text[i + 1] == '/') 129 | { 130 | i += 2; 131 | attr[istart .. i] = config.comment; 132 | continue Loop; 133 | } 134 | ++i; 135 | } 136 | attr[istart .. i] = config.comment; 137 | return SyntaxState(Syntax.comment); 138 | } 139 | } 140 | continue; 141 | } 142 | 143 | case '"': 144 | case '\'': 145 | { 146 | const istart = i; 147 | bool escape; 148 | ++i; 149 | while (i < text.length) 150 | { 151 | if (text[i] == c && !escape) 152 | { 153 | ++i; 154 | attr[istart .. i] = config.string; 155 | continue Loop; 156 | } 157 | else if (text[i] == '\\') 158 | escape ^= true; 159 | else 160 | escape = false; 161 | ++i; 162 | } 163 | attr[istart .. i] = config.string; 164 | return SyntaxState(c == '"' ? Syntax.string : 165 | Syntax.singleString); 166 | } 167 | 168 | default: 169 | if (text[i] & 0x80) 170 | goto Idstart; 171 | attr[i] = config.normattr; 172 | ++i; 173 | continue; 174 | } 175 | /* 176 | switch (syntaxState.syntax) 177 | { 178 | case Syntax.normal: 179 | break; 180 | 181 | case Syntax.string: 182 | case Syntax.singleString: 183 | break; 184 | 185 | case Syntax.comment: 186 | break; 187 | 188 | default: 189 | assert(0); 190 | } 191 | */ 192 | } 193 | return SyntaxState(Syntax.normal); 194 | } 195 | 196 | private bool isCPPKeyword(const(char)[] s) 197 | { 198 | switch (s) 199 | { 200 | case "alignas": 201 | case "const_cast": 202 | case "for": 203 | case "public": 204 | case "thread_local ": 205 | case "alignof": 206 | case "continue": 207 | case "friend": 208 | case "register": 209 | case "throw": 210 | case "asm": 211 | case "decltype": 212 | case "goto": 213 | case "reinterpret_cast": 214 | case "true ": 215 | case "auto": 216 | case "default": 217 | case "if": 218 | case "requires": 219 | case "try ": 220 | case "bool": 221 | case "delete": 222 | case "inline": 223 | case "return": 224 | case "typedef ": 225 | case "break": 226 | case "do": 227 | case "int": 228 | case "short": 229 | case "typeid ": 230 | case "case": 231 | case "double": 232 | case "long": 233 | case "signed": 234 | case "typename ": 235 | case "catch": 236 | case "dynamic_cast": 237 | case "mutable": 238 | case "sizeof": 239 | case "union ": 240 | case "char": 241 | case "else": 242 | case "namespace": 243 | case "static": 244 | case "unsigned ": 245 | case "char16_t": 246 | case "enum": 247 | case "new": 248 | case "static_assert": 249 | case "using ": 250 | case "char32_t": 251 | case "explicit": 252 | case "noexcept": 253 | case "static_cast": 254 | case "virtual ": 255 | case "class": 256 | case "export": 257 | case "nullptr": 258 | case "struct": 259 | case "void ": 260 | case "concept": 261 | case "extern": 262 | case "operator": 263 | case "switch": 264 | case "volatile ": 265 | case "const": 266 | case "false": 267 | case "private": 268 | case "template": 269 | case "wchar_t ": 270 | case "constexpr": 271 | case "float": 272 | case "protected": 273 | case "this": 274 | case "while": 275 | 276 | case "and": 277 | case "and_eq": 278 | case "bitand": 279 | case "bitor": 280 | case "compl": 281 | case "not ": 282 | case "not_eq": 283 | case "or": 284 | case "or_eq": 285 | case "xor": 286 | case "xor_eq ": 287 | 288 | case "__FILE__": 289 | case "__LINE__": 290 | return true; 291 | 292 | default: 293 | return false; 294 | } 295 | } 296 | -------------------------------------------------------------------------------- /src/med/syntaxd.d: -------------------------------------------------------------------------------- 1 | 2 | /* This version of microEmacs is based on the public domain C 3 | * version written by Dave G. Conroy. 4 | * The D programming language version is written by Walter Bright. 5 | * http://www.digitalmars.com/d/ 6 | * This program is in the public domain. 7 | */ 8 | 9 | /* This is the D syntax highligher. 10 | */ 11 | 12 | module syntaxd; 13 | 14 | import core.stdc.stdio; 15 | import core.stdc.ctype; 16 | 17 | import std.utf; 18 | 19 | import ed; 20 | import buffer; 21 | import window; 22 | import main; 23 | import display; 24 | import random; 25 | 26 | /******************************** 27 | * Returns: 28 | * starting syntax state of next line 29 | */ 30 | SyntaxState syntaxHighlightD(SyntaxState syntaxState, const(char)[] text, attr_t[] attr) 31 | { 32 | size_t i = 0; 33 | 34 | switch (syntaxState.syntax) 35 | { 36 | case Syntax.string: 37 | case Syntax.singleString: 38 | case Syntax.backtickString: 39 | { 40 | const quote = (syntaxState.syntax == Syntax.string) ? '"' : 41 | (syntaxState.syntax == Syntax.singleString) ? '\'' : 42 | '`'; 43 | const istart = i; 44 | bool escape; 45 | while (i < text.length) 46 | { 47 | if (text[i] == quote && !escape) 48 | { 49 | ++i; 50 | attr[istart .. i] = config.string; 51 | goto Loop; 52 | } 53 | else if (text[i] == '\\' && quote != '`') 54 | escape ^= true; 55 | else 56 | escape = false; 57 | ++i; 58 | } 59 | attr[istart .. i] = config.string; 60 | return SyntaxState(syntaxState.syntax); 61 | } 62 | 63 | case Syntax.comment: 64 | { 65 | if (syntaxState.nest) // it's /+ +/ nested comment 66 | { 67 | const istart = i; 68 | uint nest = syntaxState.nest; 69 | while (i < text.length) 70 | { 71 | if (text[i] == '+' && i + 1 < text.length && text[i + 1] == '/') 72 | { 73 | i += 2; 74 | --nest; 75 | if (nest == 0) 76 | { 77 | attr[istart .. i] = config.comment; 78 | goto Loop; 79 | } 80 | continue; 81 | } 82 | if (text[i] == '/' && i + 1 < text.length && text[i + 1] == '+') 83 | { 84 | i += 2; 85 | ++nest; 86 | continue; 87 | } 88 | ++i; 89 | } 90 | attr[istart .. i] = config.comment; 91 | return SyntaxState(Syntax.comment, nest); 92 | } 93 | else // it's /* */ comment 94 | { 95 | const istart = i; 96 | while (i < text.length) 97 | { 98 | if (text[i] == '*' && i + 1 < text.length && text[i + 1] == '/') 99 | { 100 | i += 2; 101 | attr[istart .. i] = config.comment; 102 | goto Loop; 103 | } 104 | ++i; 105 | } 106 | attr[istart .. i] = config.comment; 107 | return SyntaxState(Syntax.comment); 108 | } 109 | } 110 | 111 | default: 112 | break; 113 | } 114 | 115 | Loop: 116 | while (i < text.length) 117 | { 118 | const c = text[i]; 119 | switch (c) 120 | { 121 | case 'a': .. case 'z': 122 | case 'A': .. case 'Z': 123 | case '_': 124 | Idstart: 125 | { 126 | const istart = i; 127 | ++i; 128 | while (i < text.length) 129 | { 130 | const ci = text[i]; 131 | if (isalnum(ci) || ci == '_' || ci & 0x80) 132 | { 133 | ++i; 134 | continue; 135 | } 136 | break; 137 | } 138 | const id = text[istart .. i]; 139 | attr[istart .. i] = isDKeyword(id) ? config.keyword : config.normattr; 140 | continue; 141 | } 142 | 143 | case '/': 144 | { 145 | const istart = i; 146 | ++i; 147 | if (i < text.length) 148 | { 149 | if (text[i] == '/') 150 | { 151 | attr[istart .. text.length] = config.comment; 152 | return SyntaxState(Syntax.normal); 153 | } 154 | 155 | if (text[i] == '*') 156 | { 157 | ++i; 158 | while (i < text.length) 159 | { 160 | if (text[i] == '*' && i + 1 < text.length && text[i + 1] == '/') 161 | { 162 | i += 2; 163 | attr[istart .. i] = config.comment; 164 | continue Loop; 165 | } 166 | ++i; 167 | } 168 | attr[istart .. i] = config.comment; 169 | return SyntaxState(Syntax.comment); 170 | } 171 | 172 | if (text[i] == '+') 173 | { 174 | uint nest = 1; 175 | ++i; 176 | while (i < text.length) 177 | { 178 | if (text[i] == '+' && i + 1 < text.length && text[i + 1] == '/') 179 | { 180 | i += 2; 181 | --nest; 182 | if (nest == 0) 183 | { 184 | attr[istart .. i] = config.comment; 185 | continue Loop; 186 | } 187 | continue; 188 | } 189 | if (text[i] == '/' && i + 1 < text.length && text[i + 1] == '+') 190 | { 191 | i += 2; 192 | ++nest; 193 | continue; 194 | } 195 | ++i; 196 | } 197 | attr[istart .. i] = config.comment; 198 | return SyntaxState(Syntax.comment, nest); 199 | } 200 | } 201 | continue; 202 | } 203 | 204 | case '"': 205 | case '\'': 206 | case '`': 207 | { 208 | const istart = i; 209 | bool escape; 210 | ++i; 211 | while (i < text.length) 212 | { 213 | if (text[i] == c && !escape) 214 | { 215 | ++i; 216 | attr[istart .. i] = config.string; 217 | continue Loop; 218 | } 219 | else if (text[i] == '\\' && c != '`') 220 | escape ^= true; 221 | else 222 | escape = false; 223 | ++i; 224 | } 225 | attr[istart .. i] = config.string; 226 | return SyntaxState(c == '"' ? Syntax.string : 227 | c == '\'' ? Syntax.singleString : 228 | Syntax.backtickString); 229 | } 230 | 231 | default: 232 | if (text[i] & 0x80) 233 | goto Idstart; 234 | attr[i] = config.normattr; 235 | ++i; 236 | continue; 237 | } 238 | /* 239 | switch (syntaxState.syntax) 240 | { 241 | case Syntax.normal: 242 | break; 243 | 244 | case Syntax.string: 245 | case Syntax.singleString: 246 | break; 247 | 248 | case Syntax.comment: 249 | break; 250 | 251 | default: 252 | assert(0); 253 | } 254 | */ 255 | } 256 | return SyntaxState(Syntax.normal); 257 | } 258 | 259 | private bool isDKeyword(const(char)[] s) 260 | { 261 | switch (s) 262 | { 263 | case "this": 264 | case "super": 265 | case "assert": 266 | case "null": 267 | case "true": 268 | case "false": 269 | case "cast": 270 | case "new": 271 | case "delete": 272 | case "throw": 273 | case "module": 274 | case "pragma": 275 | case "typeof": 276 | case "typeid": 277 | case "template": 278 | case "void": 279 | case "byte": 280 | case "ubyte": 281 | case "short": 282 | case "ushort": 283 | case "int": 284 | case "uint": 285 | case "long": 286 | case "ulong": 287 | case "cent": 288 | case "ucent": 289 | case "float": 290 | case "double": 291 | case "real": 292 | case "bool": 293 | case "char": 294 | case "wchar": 295 | case "dchar": 296 | case "ifloat": 297 | case "idouble": 298 | case "ireal": 299 | case "cfloat": 300 | case "cdouble": 301 | case "creal": 302 | case "delegate": 303 | case "function": 304 | case "is": 305 | case "if": 306 | case "else": 307 | case "while": 308 | case "for": 309 | case "do": 310 | case "switch": 311 | case "case": 312 | case "default": 313 | case "break": 314 | case "continue": 315 | case "synchronized": 316 | case "return": 317 | case "goto": 318 | case "try": 319 | case "catch": 320 | case "finally": 321 | case "with": 322 | case "asm": 323 | case "foreach": 324 | case "foreach_reverse": 325 | case "scope": 326 | case "struct": 327 | case "class": 328 | case "interface": 329 | case "union": 330 | case "enum": 331 | case "import": 332 | case "mixin": 333 | case "static": 334 | case "final": 335 | case "const": 336 | case "alias": 337 | case "override": 338 | case "abstract": 339 | case "debug": 340 | case "deprecated": 341 | case "in": 342 | case "out": 343 | case "inout": 344 | case "lazy": 345 | case "auto": 346 | case "align": 347 | case "extern": 348 | case "private": 349 | case "package": 350 | case "protected": 351 | case "public": 352 | case "export": 353 | case "invariant": 354 | case "unittest": 355 | case "version": 356 | case "__argTypes": 357 | case "__parameters": 358 | case "ref": 359 | case "macro": 360 | case "pure": 361 | case "nothrow": 362 | case "__gshared": 363 | case "__traits": 364 | case "__vector": 365 | case "__overloadset": 366 | case "__FILE__": 367 | case "__FILE_FULL_PATH__": 368 | case "__LINE__": 369 | case "__MODULE__": 370 | case "__FUNCTION__": 371 | case "__PRETTY_FUNCTION__": 372 | case "shared": 373 | case "immutable": 374 | return true; 375 | 376 | default: 377 | return false; 378 | } 379 | } 380 | -------------------------------------------------------------------------------- /src/med/terminal.d: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* This version of microEmacs is based on the public domain C 4 | * version written by Dave G. Conroy. 5 | * The D programming language version is written by Walter Bright. 6 | * http://www.digitalmars.com/d/ 7 | * This program is in the public domain. 8 | */ 9 | 10 | 11 | version (Windows) 12 | { 13 | public import console; 14 | public import mouse; 15 | } 16 | 17 | version (Posix) 18 | { 19 | public import termio; 20 | public import xterm; 21 | } 22 | -------------------------------------------------------------------------------- /src/med/termio.d: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * The functions in this file negotiate with the operating system for 4 | * characters, and write characters in a barely buffered fashion on the display. 5 | */ 6 | 7 | module termio; 8 | 9 | version (Posix) 10 | { 11 | 12 | import core.stdc.stdio; 13 | import core.sys.posix.termios; 14 | import core.sys.posix.sys.ioctl; 15 | 16 | import ed; 17 | 18 | extern (C) void cfmakeraw(in termios*); 19 | 20 | 21 | termios ostate; /* saved tty state */ 22 | termios nstate; /* values for editor mode */ 23 | 24 | 25 | /* 26 | * This function is called once to set up the terminal device streams. 27 | * On VMS, it translates SYS$INPUT until it finds the terminal, then assigns 28 | * a channel to it and sets it raw. On CPM it is a no-op. 29 | */ 30 | void ttopen() 31 | { 32 | /* Adjust output channel */ 33 | tcgetattr(1, &ostate); /* save old state */ 34 | tcgetattr(1, &nstate); /* get base of new state */ 35 | cfmakeraw(&nstate); 36 | tcsetattr(1, TCSADRAIN, &nstate); /* set mode */ 37 | } 38 | 39 | /* 40 | * This function gets called just before we go back home to the command 41 | * interpreter. On VMS it puts the terminal back in a reasonable state. 42 | * Another no-operation on CPM. 43 | */ 44 | void ttclose() 45 | { 46 | tcsetattr(1, TCSADRAIN, &ostate); // return to original mode 47 | } 48 | 49 | /* 50 | * Write a character to the display. On VMS, terminal output is buffered, and 51 | * we just put the characters in the big array, after checking for overflow. 52 | * On CPM terminal I/O unbuffered, so we just write the byte out. Ditto on 53 | * MS-DOS (use the very very raw console output routine). 54 | */ 55 | void ttputc(char c) 56 | { 57 | fputc(c, stdout); 58 | } 59 | 60 | /* 61 | * Flush terminal buffer. Does real work where the terminal output is buffered 62 | * up. A no-operation on systems where byte at a time terminal I/O is done. 63 | */ 64 | void ttflush() 65 | { 66 | fflush(stdout); 67 | } 68 | 69 | /* 70 | * Read a character from the terminal, performing no editing and doing no echo 71 | * at all. More complex in VMS that almost anyplace else, which figures. Very 72 | * simple on CPM, because the system can do exactly what you want. 73 | */ 74 | int ttgetc() 75 | { 76 | return fgetc(stdin); 77 | } 78 | 79 | /************************** 80 | * Return TRUE if there are unread chars ready in the input. 81 | */ 82 | 83 | int ttkeysininput() 84 | { 85 | int n; 86 | ioctl(0, FIONREAD, &n); 87 | return n != 0; 88 | } 89 | 90 | /************************** 91 | * Return when there are unread chars ready in the input. 92 | */ 93 | 94 | void ttwaitkeys() 95 | { 96 | import core.sys.posix.sys.select; 97 | fd_set readfds; 98 | FD_ZERO(&readfds); 99 | FD_SET(0, &readfds); 100 | select(1, &readfds, null, null, null); 101 | } 102 | 103 | /****************************** 104 | */ 105 | 106 | void ttyield() 107 | { 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /src/med/testkbd.d: -------------------------------------------------------------------------------- 1 | 2 | module testkbd; 3 | 4 | version (Posix) 5 | { 6 | 7 | import core.stdc.stdio; 8 | import core.sys.posix.termios; 9 | import core.sys.posix.sys.ioctl; 10 | 11 | import ed; 12 | 13 | extern (C) void cfmakeraw(in termios*); 14 | 15 | 16 | termios ostate; /* saved tty state */ 17 | termios nstate; /* values for editor mode */ 18 | 19 | 20 | /* 21 | * This function is called once to set up the terminal device streams. 22 | * On VMS, it translates SYS$INPUT until it finds the terminal, then assigns 23 | * a channel to it and sets it raw. On CPM it is a no-op. 24 | */ 25 | void ttopen() 26 | { 27 | /* Adjust output channel */ 28 | tcgetattr(1, &ostate); /* save old state */ 29 | tcgetattr(1, &nstate); /* get base of new state */ 30 | cfmakeraw(&nstate); 31 | tcsetattr(1, TCSADRAIN, &nstate); /* set mode */ 32 | } 33 | 34 | /* 35 | * This function gets called just before we go back home to the command 36 | * interpreter. On VMS it puts the terminal back in a reasonable state. 37 | * Another no-operation on CPM. 38 | */ 39 | void ttclose() 40 | { 41 | tcsetattr(1, TCSADRAIN, &ostate); // return to original mode 42 | } 43 | 44 | /* 45 | * Write a character to the display. On VMS, terminal output is buffered, and 46 | * we just put the characters in the big array, after checking for overflow. 47 | * On CPM terminal I/O unbuffered, so we just write the byte out. Ditto on 48 | * MS-DOS (use the very very raw console output routine). 49 | */ 50 | void ttputc(char c) 51 | { 52 | fputc(c, stdout); 53 | } 54 | 55 | /* 56 | * Flush terminal buffer. Does real work where the terminal output is buffered 57 | * up. A no-operation on systems where byte at a time terminal I/O is done. 58 | */ 59 | void ttflush() 60 | { 61 | fflush(stdout); 62 | } 63 | 64 | /* 65 | * Read a character from the terminal, performing no editing and doing no echo 66 | * at all. More complex in VMS that almost anyplace else, which figures. Very 67 | * simple on CPM, because the system can do exactly what you want. 68 | */ 69 | int ttgetc() 70 | { 71 | return fgetc(stdin); 72 | } 73 | 74 | /************************** 75 | * Return TRUE if there are unread chars ready in the input. 76 | */ 77 | 78 | int ttkeysininput() 79 | { 80 | int n; 81 | ioctl(0, FIONREAD, &n); 82 | return n != 0; 83 | } 84 | 85 | /************************** 86 | * Return when there are unread chars ready in the input. 87 | */ 88 | 89 | void ttwaitkeys() 90 | { 91 | import core.sys.posix.sys.select; 92 | fd_set readfds; 93 | FD_ZERO(&readfds); 94 | FD_SET(0, &readfds); 95 | select(1, &readfds, null, null, null); 96 | } 97 | 98 | /****************************** 99 | */ 100 | 101 | void ttyield() 102 | { 103 | } 104 | 105 | int msm_init() 106 | { 107 | puts("\x1b[?1000h"); 108 | return true; 109 | } 110 | 111 | void msm_term() 112 | { 113 | puts("\x1b[?1000l"); 114 | } 115 | 116 | } 117 | 118 | int main() 119 | { 120 | printf("type 'x' to exit\n"); 121 | ttopen(); 122 | msm_init(); 123 | while (1) 124 | { 125 | int c = ttgetc(); 126 | if (c > ' ' && c <= '~') 127 | printf("c = '%c' x%02x\n\r", c, c); 128 | else 129 | printf("c = x%02x\n\r", c); 130 | if (c == 'x') 131 | break; 132 | } 133 | msm_term(); 134 | ttclose(); 135 | return 0; 136 | } 137 | -------------------------------------------------------------------------------- /src/med/url.d: -------------------------------------------------------------------------------- 1 | 2 | import core.stdc.stdio; 3 | import core.stdc.ctype; 4 | 5 | /********************************* 6 | * Determine if c is a valid URL character. 7 | */ 8 | int isURLchar(char c) 9 | { 10 | if (isalnum(c)) 11 | return 1; 12 | switch (c) 13 | { 14 | case '-': 15 | case '_': 16 | case '?': 17 | case '=': 18 | case '%': 19 | case '&': 20 | case '/': 21 | case '+': 22 | case '#': 23 | case '~': 24 | case '.': 25 | case ':': 26 | return 1; 27 | 28 | default: 29 | return 0; 30 | } 31 | } 32 | 33 | /****************************** 34 | * Determine if string s of length is the start of a URL. 35 | * Returns: 36 | * 0 means not a URL, >0 gives the length of the URL 37 | */ 38 | size_t isURL(const(char)[] s) 39 | { 40 | /* Must start with one of: 41 | * http:// 42 | * https:// 43 | */ 44 | 45 | if (s.length < 9 || s[6] != '/') 46 | return 0; 47 | 48 | //writefln("isURL(%s)", s); 49 | 50 | if (!((s[0] == 'h' || s[0] == 'H') && 51 | (s[1] == 't' || s[1] == 'T') && 52 | (s[2] == 't' || s[2] == 'T') && 53 | (s[3] == 'p' || s[3] == 'P'))) 54 | return 0; 55 | 56 | size_t i; 57 | if (s[4] == ':' && s[5] == '/') 58 | i = 7; 59 | else if ((s[4] == 's' || s[4] == 'S') && s[5] == ':' && s[7] == '/') 60 | i = 8; 61 | else 62 | return 0; 63 | 64 | size_t lastdot; 65 | for (; i < s.length; i++) 66 | { 67 | auto c = s[i]; 68 | if (isalnum(c)) 69 | continue; 70 | if (c == '-' || c == '_' || c == '?' || 71 | c == '=' || c == '%' || c == '&' || 72 | c == '/' || c == '+' || c == '#' || 73 | c == '~') 74 | continue; 75 | if (c == '.') 76 | { 77 | lastdot = i; 78 | continue; 79 | } 80 | break; 81 | } 82 | if (!lastdot) 83 | return 0; 84 | 85 | return i; 86 | } 87 | 88 | 89 | /**************************************************** 90 | * Determine if index is in a URL or not. 91 | */ 92 | int inURL(const(char)[] s, size_t index) 93 | { 94 | if (s.length < 9 || !isURLchar(s[index])) 95 | return 0; 96 | 97 | size_t i; 98 | size_t end = s.length - 9; 99 | if (index < end) 100 | end = index + 1; 101 | for (i = 0; i < end; ++i) 102 | { 103 | size_t j = isURL(s[i .. s.length]); 104 | if (j) 105 | { 106 | if (i <= index && index < i + j) 107 | return 1; 108 | i = i + j - 1; 109 | } 110 | } 111 | return 0; 112 | } 113 | 114 | 115 | /************************************************ 116 | * Determine URL that index is in. 117 | * Return slice of s, null if not in a URL. 118 | */ 119 | 120 | inout(char)[] getURL(inout(char)[] s, size_t index) 121 | { 122 | //printf("\ngetURL() '%.*s' \n", cast(int)s.length, s.ptr); 123 | for (size_t i = 0; i <= index; ++i) 124 | { 125 | size_t j = isURL(s[i .. s.length]); 126 | if (j) 127 | { 128 | if (i <= index && index < i + j) 129 | { 130 | return s[i .. i + j]; 131 | } 132 | i = i + j - 1; 133 | } 134 | } 135 | return null; 136 | } 137 | -------------------------------------------------------------------------------- /src/med/utf.d: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* This version of microEmacs is based on the public domain C 4 | * version written by Dave G. Conroy. 5 | * The D programming language version is written by Walter Bright. 6 | * http://dlang.org 7 | * This program is in the public domain. 8 | * https://github.com/DigitalMars/med/blob/master/src/med/uni.d 9 | */ 10 | 11 | /****************************************** 12 | * Decode Unicode character from UTF-8 string. 13 | * Advance index to be past decoded character. 14 | * Treat errors as if the first code unit is valid. 15 | * Params: 16 | * s = UTF-8 string to decode 17 | * index = index into s[] to start decoding, index is updated on return 18 | * Returns: 19 | * decoded character 20 | */ 21 | dchar decodeUTF8(const(char)[] s, ref size_t index) 22 | { 23 | const i = index; 24 | const c = s[i]; 25 | if (c <= 0x7F) 26 | { 27 | Lerr: 28 | index = i + 1; 29 | return c; 30 | } 31 | 32 | /* The following encodings are valid, except for the 5 and 6 byte 33 | * combinations: 34 | * 0xxxxxxx 35 | * 110xxxxx 10xxxxxx 36 | * 1110xxxx 10xxxxxx 10xxxxxx 37 | * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 38 | * 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 39 | * 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 40 | */ 41 | uint n; 42 | for (n = 1; ; ++n) 43 | { 44 | if (n > 4) 45 | goto Lerr; // only do the first 4 of 6 encodings 46 | if (((c << n) & 0x80) == 0) 47 | { 48 | if (n == 1) 49 | goto Lerr; 50 | break; 51 | } 52 | } 53 | 54 | // Pick off (7 - n) significant bits of first byte of octet 55 | auto V = cast(dchar)(c & ((1 << (7 - n)) - 1)); 56 | 57 | if (i + (n - 1) >= s.length) 58 | goto Lerr; // off end of string 59 | 60 | /* The following combinations are overlong, and illegal: 61 | * 1100000x (10xxxxxx) 62 | * 11100000 100xxxxx (10xxxxxx) 63 | * 11110000 1000xxxx (10xxxxxx 10xxxxxx) 64 | * 11111000 10000xxx (10xxxxxx 10xxxxxx 10xxxxxx) 65 | * 11111100 100000xx (10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx) 66 | */ 67 | const c2 = s[i + 1]; 68 | if ((c & 0xFE) == 0xC0 || 69 | (c == 0xE0 && (c2 & 0xE0) == 0x80) || 70 | (c == 0xF0 && (c2 & 0xF0) == 0x80) || 71 | (c == 0xF8 && (c2 & 0xF8) == 0x80) || 72 | (c == 0xFC && (c2 & 0xFC) == 0x80)) 73 | goto Lerr; // overlong combination 74 | 75 | for (uint j = 1; j != n; ++j) 76 | { 77 | const u = s[i + j]; 78 | if ((u & 0xC0) != 0x80) 79 | goto Lerr; // trailing bytes are 10xxxxxx 80 | V = (V << 6) | (u & 0x3F); 81 | } 82 | if (!isValidDchar(V)) 83 | goto Lerr; 84 | index = i + n; 85 | return V; 86 | } 87 | 88 | bool isValidDchar(dchar c) 89 | { 90 | return c < 0xD800 || 91 | (c > 0xDFFF && c <= 0x10FFFF && c != 0xFFFE && c != 0xFFFF); 92 | } 93 | 94 | /******************************************** 95 | * Backup in string. The reverse of decodeUTF8(). 96 | */ 97 | 98 | dchar decodeUTF8back(const(char)[] s, ref size_t index) 99 | { 100 | const i = index; 101 | if (!i) 102 | return 0; 103 | 104 | const c = s[i]; 105 | if (c <= 0x7F) 106 | { 107 | Lerr: 108 | index = i - 1; 109 | return c; 110 | } 111 | 112 | uint n; 113 | for (size_t j = i; 1; ) 114 | { 115 | if (j == 1 || i - j == 4) 116 | goto Lerr; 117 | --j; 118 | auto u = s[j]; 119 | if (u <= 0x7F) 120 | goto Lerr; 121 | if ((u & 0xC0) == 0xC0) 122 | { 123 | index = j; 124 | return 0; 125 | } 126 | } 127 | assert(0); 128 | } 129 | 130 | enum dchar replacementDchar = '\uFFFD'; 131 | 132 | char[] toUTF8(return out char[4] buf, dchar c) nothrow @nogc @safe 133 | { 134 | if (c <= 0x7F) 135 | { 136 | buf[0] = cast(char)c; 137 | return buf[0 .. 1]; 138 | } 139 | else if (c <= 0x7FF) 140 | { 141 | buf[0] = cast(char)(0xC0 | (c >> 6)); 142 | buf[1] = cast(char)(0x80 | (c & 0x3F)); 143 | return buf[0 .. 2]; 144 | } 145 | else if (c <= 0xFFFF) 146 | { 147 | if (c >= 0xD800 && c <= 0xDFFF) 148 | c = replacementDchar; 149 | 150 | L3: 151 | buf[0] = cast(char)(0xE0 | (c >> 12)); 152 | buf[1] = cast(char)(0x80 | ((c >> 6) & 0x3F)); 153 | buf[2] = cast(char)(0x80 | (c & 0x3F)); 154 | return buf[0 .. 3]; 155 | } 156 | else 157 | { 158 | if (c > 0x10FFFF) 159 | { 160 | c = replacementDchar; 161 | goto L3; 162 | } 163 | 164 | buf[0] = cast(char)(0xF0 | (c >> 18)); 165 | buf[1] = cast(char)(0x80 | ((c >> 12) & 0x3F)); 166 | buf[2] = cast(char)(0x80 | ((c >> 6) & 0x3F)); 167 | buf[3] = cast(char)(0x80 | (c & 0x3F)); 168 | return buf[0 .. 4]; 169 | } 170 | } 171 | 172 | -------------------------------------------------------------------------------- /src/med/window.d: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* This version of microEmacs is based on the public domain C 4 | * version written by Dave G. Conroy. 5 | * The D programming language version is written by Walter Bright. 6 | * http://www.digitalmars.com/d/ 7 | * This program is in the public domain. 8 | */ 9 | 10 | 11 | /* 12 | * Window management. Some of the functions are internal, and some are 13 | * attached to keys that the user actually types. 14 | */ 15 | 16 | module window; 17 | 18 | import core.memory; 19 | import std.string; 20 | 21 | import ed; 22 | import buffer; 23 | import line; 24 | import main; 25 | import terminal; 26 | import display; 27 | 28 | /* 29 | * There is a window structure allocated for every active display window. The 30 | * windows are kept in a big list, in top to bottom screen order, with the 31 | * listhead at "wheadp". Each window contains its own values of dot and mark. 32 | * The flag field contains some bits that are set by commands to guide 33 | * redisplay; although this is a bit of a compromise in terms of decoupling, 34 | * the full blown redisplay is just too expensive to run for every input 35 | * character. 36 | */ 37 | struct WINDOW { 38 | BUFFER* w_bufp; /* Buffer displayed in window */ 39 | LINE* w_linep; /* Top line in the window */ 40 | LINE* w_dotp; /* Line containing "." */ 41 | int w_doto; /* Byte offset for "." */ 42 | LINE* w_markp; /* Line containing "mark" */ 43 | int w_marko; /* Byte offset for "mark" */ 44 | int w_toprow; /* Origin 0 top row of window */ 45 | int w_ntrows; /* # of rows of text in window */ 46 | int w_force; /* If NZ, forcing row. */ 47 | ubyte w_flag; /* Flags. */ 48 | int w_startcol; /* starting column */ 49 | } 50 | 51 | enum 52 | { 53 | WFFORCE = 0x01, /* Window needs forced reframe */ 54 | WFMOVE = 0x02, /* Movement from line to line */ 55 | WFEDIT = 0x04, /* Editing within a line */ 56 | WFHARD = 0x08, /* Better do a full display */ 57 | WFMODE = 0x10, /* Update mode line. */ 58 | } 59 | 60 | __gshared WINDOW*[] windows; 61 | 62 | __gshared WINDOW* winSearchPat; // the window with highlighted search results 63 | 64 | /* !=0 means marking */ 65 | bool window_marking(WINDOW* wp) { return wp.w_markp != null; } 66 | 67 | 68 | /************************************* 69 | * Reposition dot in the current window to line "n". If the argument is 70 | * positive, it is that line. If it is negative it is that line from the 71 | * bottom. If it is 0 the window is centered (this is what the standard 72 | * redisplay code does). With no argument it defaults to 1. Bound to M-!. 73 | * Because of the default, it works like in Gosling. 74 | */ 75 | 76 | int window_reposition(bool f, int n) 77 | { 78 | curwp.w_force = n; 79 | curwp.w_flag |= WFFORCE; 80 | return (TRUE); 81 | } 82 | 83 | /* 84 | * Refresh the screen. With no argument, it just does the refresh. With an 85 | * argument it recenters "." in the current window. Bound to "C-L". 86 | */ 87 | int window_refresh(bool f, int n) 88 | { 89 | if (f == FALSE) 90 | sgarbf = TRUE; 91 | else 92 | { 93 | curwp.w_force = 0; /* Center dot. */ 94 | curwp.w_flag |= WFFORCE; 95 | } 96 | 97 | return (TRUE); 98 | } 99 | 100 | /* 101 | * The command make the next window (next => down the screen) the current 102 | * window. There are no real errors, although the command does nothing if 103 | * there is only 1 window on the screen. Bound to "C-X C-N". 104 | */ 105 | int window_next(bool f, int n) 106 | { 107 | foreach (i, wp; windows) 108 | { 109 | if (wp == curwp) 110 | { 111 | i = i + 1; 112 | if (i == windows.length) 113 | i = 0; 114 | curwp = windows[i]; 115 | curbp = curwp.w_bufp; 116 | return TRUE; 117 | } 118 | } 119 | return FALSE; 120 | } 121 | 122 | /* 123 | * This command makes the previous window (previous => up the screen) the 124 | * current window. There arn't any errors, although the command does not do a 125 | * lot if there is 1 window. 126 | */ 127 | int window_prev(bool f, int n) 128 | { 129 | foreach (i, wp; windows) 130 | { 131 | if (wp == curwp) 132 | { 133 | if (i == 0) 134 | i = windows.length; 135 | i--; 136 | curwp = windows[i]; 137 | curbp = curwp.w_bufp; 138 | return TRUE; 139 | } 140 | } 141 | return FALSE; 142 | } 143 | 144 | /* 145 | * This command moves the current window down by "arg" lines. Recompute the 146 | * top line in the window. The move up and move down code is almost completely 147 | * the same; most of the work has to do with reframing the window, and picking 148 | * a new dot. We share the code by having "move down" just be an interface to 149 | * "move up". Magic. Bound to "C-X C-N". 150 | */ 151 | int window_mvdn(bool f, int n) 152 | { 153 | return window_mvup(f, -n); 154 | } 155 | 156 | /* 157 | * Move the current window up by "arg" lines. Recompute the new top line of 158 | * the window. Look to see if "." is still on the screen. If it is, you win. 159 | * If it isn't, then move "." to center it in the new framing of the window 160 | * (this command does not really move "."; it moves the frame). Bound to 161 | * "C-X C-P". 162 | */ 163 | int window_mvup(bool f, int n) 164 | { 165 | LINE *lp; 166 | int i; 167 | 168 | lp = curwp.w_linep; 169 | 170 | if (n < 0) 171 | { 172 | while (n++ && lp!=curbp.b_linep) 173 | lp = lforw(lp); 174 | } 175 | else 176 | { 177 | while (n-- && lback(lp)!=curbp.b_linep) 178 | lp = lback(lp); 179 | } 180 | 181 | curwp.w_linep = lp; /* new top line of window */ 182 | curwp.w_flag |= WFHARD; /* Mode line is OK. */ 183 | 184 | for (i = 0; i < curwp.w_ntrows; ++i) 185 | { 186 | if (lp == curwp.w_dotp) 187 | return (TRUE); 188 | if (lp == curbp.b_linep) 189 | break; 190 | lp = lforw(lp); 191 | } 192 | 193 | lp = curwp.w_linep; 194 | i = curwp.w_ntrows/2; 195 | 196 | while (i-- && lp != curbp.b_linep) 197 | lp = lforw(lp); 198 | 199 | curwp.w_dotp = lp; 200 | curwp.w_doto = 0; 201 | return (TRUE); 202 | } 203 | 204 | /* 205 | * This command makes the current window the only window on the screen. Bound 206 | * to "C-X 1". Try to set the framing so that "." does not have to move on the 207 | * display. Some care has to be taken to keep the values of dot and mark in 208 | * the buffer structures right if the destruction of a window makes a buffer 209 | * become undisplayed. 210 | */ 211 | int window_only(bool f, int n) 212 | { 213 | foreach (wp; windows) 214 | { 215 | if (wp != curwp) 216 | { 217 | if (--wp.w_bufp.b_nwnd == 0) { 218 | wp.w_bufp.b_dotp = wp.w_dotp; 219 | wp.w_bufp.b_doto = wp.w_doto; 220 | wp.w_bufp.b_markp = wp.w_markp; 221 | wp.w_bufp.b_marko = wp.w_marko; 222 | } 223 | if (winSearchPat == wp) 224 | winSearchPat = null; 225 | //delete wp; 226 | core.memory.GC.free(wp); 227 | } 228 | } 229 | windows = windows[0 .. 1]; 230 | windows[0] = curwp; 231 | 232 | auto lp = curwp.w_linep; 233 | auto i = curwp.w_toprow; 234 | while (i!=0 && lback(lp)!=curbp.b_linep) { 235 | --i; 236 | lp = lback(lp); 237 | } 238 | curwp.w_toprow = 0; 239 | curwp.w_ntrows = term.t_nrow - 2; 240 | curwp.w_linep = lp; 241 | curwp.w_flag |= WFMODE|WFHARD; 242 | return (TRUE); 243 | } 244 | 245 | /* 246 | * Split the current window. A window smaller than 3 lines cannot be split. 247 | * The only other error that is possible is a "malloc" failure allocating the 248 | * structure for the new window. Bound to "C-X 2". 249 | */ 250 | int window_split(bool f, int n) 251 | { 252 | LINE *lp; 253 | int ntru; 254 | int ntrl; 255 | int ntrd; 256 | WINDOW *wp1; 257 | WINDOW *wp2; 258 | 259 | if (curwp.w_ntrows < 3) { 260 | mlwrite("Cannot split a %d line window", curwp.w_ntrows); 261 | return (FALSE); 262 | } 263 | auto wp = new WINDOW; 264 | ++curbp.b_nwnd; /* Displayed twice. */ 265 | wp.w_bufp = curbp; 266 | wp.w_dotp = curwp.w_dotp; 267 | wp.w_doto = curwp.w_doto; 268 | wp.w_markp = curwp.w_markp; 269 | wp.w_marko = curwp.w_marko; 270 | ntru = (curwp.w_ntrows-1) / 2; /* Upper size */ 271 | ntrl = (curwp.w_ntrows-1) - ntru; /* Lower size */ 272 | lp = curwp.w_linep; 273 | ntrd = 0; 274 | while (lp != curwp.w_dotp) { 275 | ++ntrd; 276 | lp = lforw(lp); 277 | } 278 | lp = curwp.w_linep; 279 | if (ntrd <= ntru) { /* Old is upper window. */ 280 | if (ntrd == ntru) /* Hit mode line. */ 281 | lp = lforw(lp); 282 | curwp.w_ntrows = ntru; 283 | // Insert wp after curwp 284 | foreach (i, w; windows) 285 | { if (w == curwp) 286 | { 287 | windows = windows[0 .. i + 1] ~ wp ~ windows[i + 1 .. $]; 288 | break; 289 | } 290 | } 291 | wp.w_toprow = curwp.w_toprow+ntru+1; 292 | wp.w_ntrows = ntrl; 293 | } else { /* Old is lower window */ 294 | // Insert wp before curwp 295 | foreach (i, w; windows) 296 | { if (w == curwp) 297 | { 298 | windows = windows[0 .. i] ~ wp ~ windows[i .. $]; 299 | break; 300 | } 301 | } 302 | 303 | wp.w_toprow = curwp.w_toprow; 304 | wp.w_ntrows = ntru; 305 | ++ntru; /* Mode line. */ 306 | curwp.w_toprow += ntru; 307 | curwp.w_ntrows = ntrl; 308 | while (ntru--) 309 | lp = lforw(lp); 310 | } 311 | curwp.w_linep = lp; /* Adjust the top lines */ 312 | wp.w_linep = lp; /* if necessary. */ 313 | curwp.w_flag |= WFMODE|WFHARD; 314 | wp.w_flag |= WFMODE|WFHARD; 315 | return (TRUE); 316 | } 317 | 318 | /* 319 | * Enlarge the current window. Find the window that loses space. Make sure it 320 | * is big enough. If so, hack the window descriptions, and ask redisplay to do 321 | * all the hard work. You don't just set "force reframe" because dot would 322 | * move. Bound to "C-X Z". 323 | */ 324 | int window_enlarge(bool f, int n) 325 | { 326 | WINDOW *adjwp; 327 | LINE *lp; 328 | bool prev; 329 | 330 | if (n < 0) 331 | return (window_shrink(f, -n)); 332 | 333 | if (windows.length == 1) { 334 | mlwrite("Only one window"); 335 | return (FALSE); 336 | } 337 | 338 | foreach (i, wp; windows) 339 | { 340 | if (wp == curwp) 341 | { 342 | if (i == windows.length - 1) 343 | { 344 | adjwp = windows[i - 1]; 345 | prev = true; 346 | } 347 | else 348 | { 349 | adjwp = windows[i + 1]; 350 | prev = false; 351 | } 352 | break; 353 | } 354 | } 355 | 356 | if (adjwp.w_ntrows <= n) { 357 | mlwrite("Impossible enlarge change"); 358 | return (FALSE); 359 | } 360 | if (!prev) { // Shrink below. 361 | lp = adjwp.w_linep; 362 | for (int i=0; i 0) 113 | { 114 | L1: 115 | col = 0; 116 | lasti = 0; 117 | inword = 0; 118 | for (i = 0; i < llength(curwp.w_dotp); i++) 119 | { 120 | c = lgetc(curwp.w_dotp, i); 121 | if (c == ' ' || c == '\t') 122 | { 123 | if (inword) 124 | lasti = i; 125 | inword = 0; 126 | } 127 | else 128 | { 129 | inword = 1; 130 | } 131 | col = getcol(curwp.w_dotp, i); 132 | if (col >= term.t_ncol && lasti) 133 | { 134 | if (!forwchar(0, lasti - curwp.w_doto)) 135 | goto err; 136 | if (!random_newline(0,1)) 137 | goto err; 138 | 139 | /* Remove leading whitespace from new line */ 140 | while (1) 141 | { 142 | if (!llength(curwp.w_dotp)) 143 | break; 144 | c = lgetc(curwp.w_dotp, 0); 145 | if (c == ' ' || c == '\t') 146 | { 147 | if (!random_forwdel(0, 1)) 148 | goto err; 149 | } 150 | else 151 | break; 152 | } 153 | 154 | /* Match indenting of original line (oldp) */ 155 | oldp = lback(curwp.w_dotp); 156 | for (j = 0; j < llength(oldp); j++) 157 | { 158 | c = lgetc(oldp, j); 159 | if (c == ' ' || c == '\t') 160 | { 161 | if (!line_insert(1, c)) 162 | goto err; 163 | } 164 | else 165 | break; 166 | } 167 | 168 | goto L1; 169 | } 170 | } 171 | if (!forwline(0, 1)) 172 | goto err; 173 | } 174 | if (window_marking(curwp)) 175 | { 176 | if (dotosave > llength(dotpsave)) 177 | dotosave = llength(dotpsave); 178 | curwp.w_dotp = dotpsave; 179 | curwp.w_doto = dotosave; 180 | } 181 | return true; 182 | 183 | err: 184 | return false; 185 | } 186 | 187 | /************************* 188 | * Select word that the cursor is on. 189 | */ 190 | 191 | int word_select(bool f, int n) 192 | { 193 | int inw; 194 | int s; 195 | 196 | inw = inword(); 197 | do 198 | s = backchar(false, 1); 199 | while (s && inword() == inw); 200 | 201 | return s && 202 | forwchar(false,1) && 203 | basic_setmark(false,1) && 204 | word_forw(f,n); 205 | } 206 | 207 | /****************************** 208 | * Select line that the cursor is on. 209 | */ 210 | 211 | int word_lineselect(bool f, int n) 212 | { 213 | return (curwp.w_doto == 0 || gotobol(false,1)) && 214 | basic_setmark(false,1) && 215 | forwline(f,n); 216 | } 217 | 218 | /* 219 | * Move the cursor backward by "n" words. All of the details of motion are 220 | * performed by the "backchar" and "forwchar" routines. Error if you try to 221 | * move beyond the buffers. 222 | */ 223 | int word_back(bool f, int n) 224 | { 225 | if (n < 0) 226 | return (word_forw(f, -n)); 227 | if (backchar(false, 1) == false) 228 | return (false); 229 | while (n--) { 230 | auto inw = inword(); 231 | do 232 | if (backchar(false, 1) == false) 233 | return (false); 234 | while (inword() == inw); 235 | } 236 | return (forwchar(false, 1)); 237 | } 238 | 239 | /* 240 | * Move the cursor forward by the specified number of words. All of the motion 241 | * is done by "forwchar". Error if you try and move beyond the buffer's end. 242 | */ 243 | int word_forw(bool f, int n) 244 | { 245 | if (n < 0) 246 | return (word_back(f, -n)); 247 | while (n--) { 248 | auto inw = inword(); 249 | do 250 | if (forwchar(false, 1) == false) 251 | return (false); 252 | while (inword() == inw); 253 | } 254 | return (true); 255 | } 256 | 257 | /* 258 | * Move the cursor forward by the specified number of words. As you move, 259 | * convert any characters to upper case. Error if you try and move beyond the 260 | * end of the buffer. Bound to "M-U". 261 | */ 262 | int word_upper(bool f, int n) 263 | { 264 | return word_setcase(f,n,0); 265 | } 266 | 267 | /* 268 | * Move the cursor forward by the specified number of words. As you move 269 | * convert characters to lower case. Error if you try and move over the end of 270 | * the buffer. Bound to "M-L". 271 | */ 272 | int word_lower(bool f, int n) 273 | { 274 | return word_setcase(f,n,1); 275 | } 276 | 277 | /************************* 278 | * Move the cursor forward by the specified number of words. As you move 279 | * convert the first character of the word to upper case, and subsequent 280 | * characters to lower case. Error if you try and move past the end of the 281 | * buffer. Bound to "M-C". 282 | */ 283 | 284 | int capword(bool f, int n) 285 | { 286 | return word_setcase(f,n,2); 287 | } 288 | 289 | private int word_setcase(bool f, int n, int flag) 290 | { 291 | char c; 292 | 293 | if (n < 0) 294 | return (false); 295 | while (n--) { 296 | while (inword() == false) { 297 | if (forwchar(false, 1) == false) 298 | return (false); 299 | } 300 | if (flag == 2 && inword() != false) { 301 | c = lgetc(curwp.w_dotp, curwp.w_doto); 302 | if (isLower(c)) 303 | { c -= 'a'-'A'; 304 | lputc(curwp.w_dotp, curwp.w_doto, c); 305 | line_change(WFHARD); 306 | } 307 | if (forwchar(false, 1) == false) 308 | return (false); 309 | } 310 | while (inword() != false) { 311 | c = lgetc(curwp.w_dotp, curwp.w_doto); 312 | final switch (flag) 313 | { case 0: 314 | if (isLower(c)) { 315 | c -= 'a'-'A'; 316 | goto L1; 317 | } 318 | break; 319 | case 1: 320 | case 2: 321 | if (isUpper(c)) { 322 | c += 'a'-'A'; 323 | L1: lputc(curwp.w_dotp, curwp.w_doto, c); 324 | line_change(WFHARD); 325 | } 326 | break; 327 | } 328 | if (forwchar(false, 1) == false) 329 | return (false); 330 | } 331 | } 332 | return (true); 333 | } 334 | 335 | /* 336 | * Kill forward by "n" words. Remember the location of dot. Move forward by 337 | * the right number of words. Put dot back where it was and issue the kill 338 | * command for the right number of characters. Bound to "M-D". 339 | */ 340 | int delfword(bool f, int n) 341 | { 342 | int size; 343 | LINE* dotp; 344 | int doto; 345 | 346 | if (n < 0) 347 | return (false); 348 | dotp = curwp.w_dotp; 349 | doto = curwp.w_doto; 350 | size = 0; 351 | while (n--) { 352 | while (inword() == false) { 353 | if (forwchar(false, 1) == false) 354 | return (false); 355 | ++size; 356 | } 357 | while (inword() != false) { 358 | if (forwchar(false, 1) == false) 359 | return (false); 360 | ++size; 361 | } 362 | } 363 | curwp.w_dotp = dotp; 364 | curwp.w_doto = doto; 365 | return (line_delete(size, true)); 366 | } 367 | 368 | /* 369 | * Kill backwards by "n" words. Move backwards by the desired number of words, 370 | * counting the characters. When dot is finally moved to its resting place, 371 | * fire off the kill command. Bound to "M-Rubout" and to "M-Backspace". 372 | */ 373 | int delbword(bool f, int n) 374 | { 375 | int size; 376 | 377 | if (n < 0) 378 | return (false); 379 | if (backchar(false, 1) == false) 380 | return (false); 381 | size = 0; 382 | while (n--) { 383 | while (inword() == false) { 384 | if (backchar(false, 1) == false) 385 | return (false); 386 | ++size; 387 | } 388 | while (inword() != false) { 389 | if (backchar(false, 1) == false) 390 | return (false); 391 | ++size; 392 | } 393 | } 394 | if (forwchar(false, 1) == false) 395 | return false; 396 | return line_delete(size, true); 397 | } 398 | 399 | /* 400 | * Return true if the character at dot is a character that is considered to be 401 | * part of a word. The word character list is hard coded. Should be setable. 402 | * This routine MUST return only a 1 or a 0. 403 | */ 404 | bool inword() 405 | { 406 | if (curwp.w_doto == llength(curwp.w_dotp)) 407 | return false; 408 | auto c = lgetc(curwp.w_dotp, curwp.w_doto); 409 | return (isAlphaNum(c) || 410 | c=='$' || c=='_'); /* For identifiers */ 411 | } 412 | -------------------------------------------------------------------------------- /win32.mak: -------------------------------------------------------------------------------- 1 | #_ win32.mak 2 | # Build win32 version of microemacs 3 | # Needs Digital Mars D compiler to build, available free from: 4 | # http://www.digitalmars.com/d/ 5 | 6 | DMD=dmd 7 | DEL=del 8 | S=src\med 9 | O=obj 10 | B=bin 11 | 12 | TARGET=med 13 | 14 | //DFLAGS=-g -Isrc/med $(CONF) 15 | DFLAGS=-O -Isrc/med $(CONF) 16 | LFLAGS=-L/map/co 17 | #DFLAGS= 18 | #LFLAGS= 19 | 20 | .d.obj : 21 | $(DMD) -c $(DFLAGS) $* 22 | 23 | SRC= $S\ed.d $S\basic.d $S\buffer.d $S\display.d $S\file.d $S\fileio.d $S\line.d \ 24 | $S\random.d $S\region.d $S\search.d $S\spawn.d $S\terminal.d \ 25 | $S\window.d $S\word.d $S\main.d $S\more.d $S\disprev.d \ 26 | $S\termio.d $S\xterm.d $S\syntaxd.d $S\syntaxc.d $S\syntaxcpp.d \ 27 | $S\tcap.d $S\console.d $S\mouse.d $S\disp.d $S\url.d $S\utf.d $S\regexp.d 28 | 29 | 30 | OBJ= $O\ed.obj $O\basic.obj $O\buffer.obj $O\display.obj $O\file.obj $O\fileio.obj $O\line.obj \ 31 | $O\random.obj $O\region.obj $O\search.obj $O\spawn.obj $O\terminal.obj \ 32 | $O\window.obj $O\word.obj $O\main.obj $O\more.obj $O\disprev.obj \ 33 | $O\termio.obj $O\xterm.obj $O\syntaxd.obj $O\syntaxc.obj $O\syntaxcpp.obj \ 34 | $O\tcap.obj $O\console.obj $O\mouse.obj $O\disp.obj $O\url.obj $O\utf.obj $O\regexp.obj 35 | 36 | SOURCE= $(SRC) win32.mak linux.mak me.html README.md 37 | 38 | all: $B\$(TARGET).exe 39 | 40 | ################################################# 41 | 42 | $B\$(TARGET).exe : $(OBJ) 43 | $(DMD) -of$B\$(TARGET).exe $(OBJ) $(LFLAGS) 44 | 45 | $O\ed.obj: $S\ed.d 46 | $(DMD) -c $(DFLAGS) -od$O $S\ed.d 47 | 48 | $O\basic.obj: $S\basic.d 49 | $(DMD) -c $(DFLAGS) -od$O $S\basic.d 50 | 51 | $O\buffer.obj: $S\buffer.d 52 | $(DMD) -c $(DFLAGS) -od$O $S\buffer.d 53 | 54 | $O\console.obj: $S\console.d 55 | $(DMD) -c $(DFLAGS) -od$O $S\console.d 56 | 57 | $O\disp.obj: $S\disp.d 58 | $(DMD) -c $(DFLAGS) -od$O $S\disp.d 59 | 60 | $O\display.obj: $S\display.d 61 | $(DMD) -c $(DFLAGS) -od$O $S\display.d 62 | 63 | $O\file.obj: $S\file.d 64 | $(DMD) -c $(DFLAGS) -od$O $S\file.d 65 | 66 | $O\fileio.obj: $S\fileio.d 67 | $(DMD) -c $(DFLAGS) -od$O $S\fileio.d 68 | 69 | $O\line.obj: $S\line.d 70 | $(DMD) -c $(DFLAGS) -od$O $S\line.d 71 | 72 | $O\mouse.obj: $S\mouse.d 73 | $(DMD) -c $(DFLAGS) -od$O $S\mouse.d 74 | 75 | $O\random.obj: $S\random.d 76 | $(DMD) -c $(DFLAGS) -od$O $S\random.d 77 | 78 | $O\regexp.obj: $S\regexp.d 79 | $(DMD) -c $(DFLAGS) -od$O $S\regexp.d 80 | 81 | $O\region.obj: $S\region.d 82 | $(DMD) -c $(DFLAGS) -od$O $S\region.d 83 | 84 | $O\search.obj: $S\search.d 85 | $(DMD) -c $(DFLAGS) -od$O $S\search.d 86 | 87 | $O\spawn.obj: $S\spawn.d 88 | $(DMD) -c $(DFLAGS) -od$O $S\spawn.d 89 | 90 | $O\syntaxd.obj: $S\syntaxd.d 91 | $(DMD) -c $(DFLAGS) -od$O $S\syntaxd.d 92 | 93 | $O\syntaxc.obj: $S\syntaxc.d 94 | $(DMD) -c $(DFLAGS) -od$O $S\syntaxc.d 95 | 96 | $O\syntaxcpp.obj: $S\syntaxcpp.d 97 | $(DMD) -c $(DFLAGS) -od$O $S\syntaxcpp.d 98 | 99 | $O\terminal.obj: $S\terminal.d 100 | $(DMD) -c $(DFLAGS) -od$O $S\terminal.d 101 | 102 | $O\termio.obj: $S\termio.d 103 | $(DMD) -c $(DFLAGS) -od$O $S\termio.d 104 | 105 | $O\url.obj: $S\url.d 106 | $(DMD) -c $(DFLAGS) -od$O $S\url.d 107 | 108 | $O\utf.obj: $S\utf.d 109 | $(DMD) -c $(DFLAGS) -od$O $S\utf.d 110 | 111 | $O\window.obj: $S\window.d 112 | $(DMD) -c $(DFLAGS) -od$O $S\window.d 113 | 114 | $O\word.obj: $S\word.d 115 | $(DMD) -c $(DFLAGS) -od$O $S\word.d 116 | 117 | $O\main.obj: $S\main.d 118 | $(DMD) -c $(DFLAGS) -od$O $S\main.d 119 | 120 | $O\more.obj: $S\more.d 121 | $(DMD) -c $(DFLAGS) -od$O $S\more.d 122 | 123 | $O\disprev.obj: $S\disprev.d 124 | $(DMD) -c $(DFLAGS) -od$O $S\disprev.d 125 | 126 | $O\tcap.obj: $S\tcap.d 127 | $(DMD) -c $(DFLAGS) -od$O $S\tcap.d 128 | 129 | $O\xterm.obj: $S\xterm.d 130 | $(DMD) -c $(DFLAGS) -od$O $S\xterm.d 131 | 132 | ################################### 133 | 134 | clean: 135 | del $(OBJ) $B\$(TARGET).map 136 | 137 | 138 | tolf: 139 | tolf $(SOURCE) 140 | 141 | 142 | detab: 143 | detab $(SRC) 144 | 145 | 146 | zip: tolf detab 147 | $(DEL) me.zip 148 | zip32 me $(SOURCE) 149 | 150 | 151 | git: tolf detab win32.mak 152 | \putty\pscp -i c:\.ssh\colossus.ppk $(SRC) walter@mercury:dm/med/src/med 153 | \putty\pscp -i c:\.ssh\colossus.ppk win32.mak linux.mak me.html README.md walter@mercury:dm/med/ 154 | 155 | --------------------------------------------------------------------------------