├── .github └── workflows │ └── workflow.yaml ├── .gitignore ├── .gitmodules ├── Makefile ├── README.md ├── include ├── efivim.h ├── lauxlib.h ├── lua.h └── lualib.h ├── src └── efivim.c ├── vim.dec ├── vim.dsc └── vim.inf /.github/workflows/workflow.yaml: -------------------------------------------------------------------------------- 1 | name: VIM.EFI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: checkout 10 | uses: actions/checkout@v3 11 | with: 12 | submodules: recursive 13 | 14 | - name: variables 15 | id: variables 16 | run: echo "name=$(git describe --always --tags)" >> $GITHUB_OUTPUT 17 | 18 | - name: dependencies 19 | run: | 20 | sudo apt-get update 21 | sudo apt-get install -y build-essential nasm mtools gdisk 22 | 23 | - name: build 24 | run: 25 | make vim.efi vim.img.gz 26 | 27 | - name: release 28 | uses: softprops/action-gh-release@v1 29 | if: startsWith(github.ref, 'refs/tags/') 30 | with: 31 | name: ${{ steps.variables.outputs.name }} 32 | tag_name: ${{ steps.variables.outputs.name }} 33 | files: | 34 | vim.efi 35 | vim.img.gz 36 | 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .edk2 2 | edk2 3 | vim 4 | vim.efi 5 | vim.img 6 | vim.img.gz 7 | 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "vim"] 2 | path = vim 3 | url = https://github.com/vim/vim.git 4 | [submodule "edk2"] 5 | path = edk2 6 | url = https://github.com/tianocore/edk2.git 7 | [submodule "edk2-libc"] 8 | path = edk2-libc 9 | url = https://github.com/tianocore/edk2-libc.git 10 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #TARGET=DEBUG 2 | TARGET=RELEASE 3 | ARCH=X64 4 | TOOLCHAIN=GCC5 5 | PLATFORM=vim.dsc 6 | MODULE=vim.inf 7 | 8 | SGDISK=/sbin/sgdisk 9 | OVMF=/usr/share/ovmf/OVMF.fd 10 | 11 | EFIBIN=vim.efi 12 | EFIIMG=vim.img 13 | BUILDDIR=edk2/Build/AppPkg/$(TARGET)_$(TOOLCHAIN)/$(ARCH) 14 | 15 | APP=$(BUILDDIR)/$(EFIBIN) 16 | 17 | $(EFIBIN): $(APP) 18 | cp $? $@ 19 | 20 | qemu: $(EFIIMG) 21 | qemu-system-x86_64 -bios $(OVMF) -enable-kvm -serial mon:stdio -net none -drive format=raw,file=$? 22 | 23 | $(EFIIMG).gz: $(EFIIMG) 24 | gzip -9 < $< > $@ 25 | 26 | $(EFIIMG): $(APP) 27 | # 48M 28 | test -e $@ || (dd if=/dev/zero of=$@ bs=512 count=93750 2>/dev/null && \ 29 | $(SGDISK) -Z $@ >/dev/null && \ 30 | $(SGDISK) -N 1 $@ >/dev/null && \ 31 | $(SGDISK) -t 1:ef00 $@ >/dev/null && \ 32 | $(SGDISK) -c 1:"EFI" $@ >/dev/null && \ 33 | $(SGDISK) -v $@ >/dev/null && \ 34 | $(SGDISK) -p $@ && \ 35 | mformat -i $@@@1M -v EFI -F -h 32 -t 44 -n 64 -c 1 && \ 36 | mmd -i $@@@1M efi && \ 37 | mmd -i $@@@1M efi/tools \ 38 | ) 39 | mcopy -o -i $@@@1M $(APP) ::efi/tools/vim.efi 40 | touch $@ 41 | 42 | $(APP): edk2 vim 43 | bash -c 'pushd edk2; \ 44 | export WORKSPACE="$(PWD)/edk2" PACKAGES_PATH="$(PWD):$(PWD)/edk2-libc"; \ 45 | source ./edksetup.sh; \ 46 | : hack to patch out -Werror for lua build; \ 47 | sed -i -e "/GCC_ALL_CC_FLAGS/s/-Werror //g" Conf/tools_def.txt; \ 48 | popd; \ 49 | build -n 4 -a $(ARCH) -p $(PLATFORM) -m $(MODULE) -b $(TARGET) -t $(TOOLCHAIN); \ 50 | ' 51 | 52 | .PHONY: vim 53 | vim: vim/src/auto/config.h 54 | 55 | vim/src/auto/config.h: 56 | touch $@ 57 | 58 | edk2: .edk2 59 | touch $@ 60 | 61 | .edk2: 62 | make -C edk2/BaseTools 63 | touch $@ 64 | 65 | clean: 66 | rm -f $(EFIBIN) $(EFIIMG) 67 | rm -rf $(BUILDDIR) 68 | 69 | nuke: clean 70 | rm -f .edk2 71 | git -C edk2 clean -df 72 | rm -f vim/src/auto/config.h 73 | git -C vim clean -df 74 | 75 | .PHONY: qemu clean nuke 76 | 77 | .DELETE_ON_ERROR: 78 | 79 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VIM.EFI 2 | 3 | this repo is a hack to run [Vim](https://github.com/vim/vim) in a UEFI environment. 4 | 5 | ## building 6 | 7 | at the time of writing, you can build VIM.EFI on debian 11 (bullseye). 8 | 9 | you will need at least git, make and gcc. **TODO**: finish documenting what's needed 10 | 11 | sudo apt install build-essential nasm mtools gdisk 12 | 13 | to build VIM.EFI clone this repo and execute `make`. 14 | 15 | git clone --depth=1 --recursive https://github.com/mischief/efivim 16 | cd efivim 17 | make 18 | 19 | ## running 20 | 21 | to run VIM.EFI, copy `vim.efi` to the ESP and execute it from your UEFI shell. 22 | 23 | to try out VIM.EFI in qemu, execute `make qemu`, and type 'vim' in the UEFI shell prompt. 24 | 25 | ## credits 26 | 27 | originally whipped up by ya boy @mischief when he should have been doing real work at his day job 28 | 29 | thank you, @brammool for making an exellent text editor, and for helping those poor Ugandan children. 30 | 31 | shout out to @mjg59 - stay cool brother. 32 | 33 | -------------------------------------------------------------------------------- /include/efivim.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define USR_VIMRC_FILE "fs0:\\.vimrc" 9 | #define USR_EXRC_FILE "fs0:\\.exrc" 10 | #define VIMINFO_FILE "fs0:\\.viminfo" 11 | #define FTOFF_FILE "ftoff.vim" 12 | #define INDOFF_FILE "indoff.vim" 13 | #define FILETYPE_FILE "filetype.vim" 14 | #define FTPLUGIN_FILE "ftplugin.vim" 15 | #define FTPLUGOF_FILE "ftplugof.vim" 16 | #define INDENT_FILE "indent.vim" 17 | 18 | #define SYNTAX_FNAME "fs0:\\vim\\vimfiles\\syntax\\%s.vim" 19 | #define SYS_VIMRC_FILE "fs0:\\vim\\vimfiles\\vimrc" 20 | #define VIM_DEFAULTS_FILE "fs0:\\vim\\vimfiles\\defaults.vim" 21 | 22 | #define EVIM_FILE "evim.vim" 23 | #define VIMRC_FILE ".vimrc" 24 | #define EXRC_FILE ".exrc" 25 | 26 | #define DFLT_BDIR "." 27 | #define DFLT_VDIR "." 28 | #define DFLT_DIR "." 29 | #define DFLT_RUNTIMEPATH "." 30 | #define DFLT_HELPFILE "notexist" 31 | #define DFLT_MAXMEM (2*1024) 32 | #define DFLT_MAXMEMTOT (10*1024) 33 | 34 | #define DFLT_ERRORFILE "errors.err" 35 | 36 | #define BASENAMELEN 128 37 | 38 | #define TEMPNAME "efi_tmp.XXXXXX" 39 | #define TEMPNAMELEN 128 40 | 41 | #define mch_rmdir(x) rmdir((char *)(x)) 42 | #define vim_mkdir(x, y) mkdir((char *)(x), y) 43 | 44 | /* vim mch fns */ 45 | void mch_early_init(void); 46 | int mch_init(void); 47 | void mch_exit(int); 48 | void mch_suspend(void); 49 | void mch_breakcheck(int); 50 | void mch_hide(unsigned char *name); 51 | 52 | int mch_get_shellsize(void); 53 | void mch_set_shellsize(void); 54 | void mch_new_shellsize(void); 55 | 56 | void mch_get_host_name(unsigned char *s, int len); 57 | long mch_get_pid(void); 58 | 59 | unsigned char* mch_getenv(unsigned char *name); 60 | 61 | int mch_has_wildcard(unsigned char *p); 62 | int mch_has_exp_wildcard(unsigned char *p); 63 | 64 | int mch_expandpath(void *gap /* garray_T* */, unsigned char *pat, int flags); 65 | 66 | long mch_getperm(unsigned char *name); 67 | int mch_setperm(unsigned char *name, long perm); 68 | 69 | int mch_nodetype(unsigned char *name); 70 | 71 | int mch_screenmode(unsigned char *arg); 72 | int mch_check_win(int argc, char **argv); 73 | void mch_settitle(unsigned char *title, unsigned char *icon); 74 | void mch_restore_title(int which); 75 | int mch_can_restore_icon(void); 76 | int mch_can_restore_title(void); 77 | void mch_setmouse(int on); 78 | 79 | void mch_delay(long msec, int ignoreinput); 80 | int mch_inchar(unsigned char *buf, int maxlen, long wtime, int tb_change_cnt); 81 | void mch_write(unsigned char *s, int len); 82 | int mch_char_avail(void); 83 | 84 | int mch_rename(const char *src, const char *dest); 85 | int mch_remove(unsigned char *name); 86 | int mch_isdir(unsigned char *name); 87 | int mch_dirname(unsigned char *buf, int len); 88 | int mch_chdir(char *path); 89 | long mch_getperm(unsigned char *name); 90 | int mch_isFullName(unsigned char *fname); 91 | int mch_FullName(unsigned char *fname, unsigned char *buf, int len, int force); 92 | 93 | int mch_input_isatty(void); 94 | void mch_settmode(int tmode); 95 | 96 | int mch_can_exe(unsigned char *name, unsigned char **path, int use_path); 97 | int mch_call_shell(unsigned char *cmd, int options); 98 | int mch_get_user_name(unsigned char *s, int len); 99 | 100 | /* misc stuff */ 101 | int putenv(const char *string); 102 | 103 | void slash_adjust(unsigned char *p); 104 | 105 | -------------------------------------------------------------------------------- /include/lauxlib.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | -------------------------------------------------------------------------------- /include/lua.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | -------------------------------------------------------------------------------- /include/lualib.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | -------------------------------------------------------------------------------- /src/efivim.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include "efivim.h" 11 | #include "vim.h" 12 | 13 | #define where(format, ...) do{DEBUG((EFI_D_INFO, "\n%s> " format "\n", __func__, ##__VA_ARGS__));}while(0) 14 | 15 | EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *sto; 16 | UINTN cols; 17 | UINTN rows; 18 | 19 | // current index in fgmap 20 | unsigned char fgcol; 21 | // current index in bgmap 22 | unsigned char bgcol; 23 | 24 | // index is ansi code, value is uefi code 25 | UINTN fgmap[] = { 26 | // black 27 | 0x0, 28 | // red 29 | 0x4, 30 | // green 31 | 0x2, 32 | // yellow 33 | 0xe, 34 | // blue 35 | 0x1, 36 | // magenta 37 | 0x5, 38 | // cyan 39 | 0x3, 40 | // white 41 | 0xf, 42 | }; 43 | 44 | UINTN bgmap[] = { 45 | // black 46 | 0x00, 47 | // red 48 | 0x40, 49 | // green 50 | 0x20, 51 | // yellow - uefi lacks yellow bg so this is actually the brown color code. 52 | 0x60, 53 | // blue 54 | 0x10, 55 | // magenta 56 | 0x50, 57 | // cyan 58 | 0x30, 59 | // white - uefi lacks white bg so this is actually light gray. 60 | 0x70, 61 | }; 62 | 63 | static EFI_STATUS 64 | setattr(void) 65 | { 66 | EFI_STATUS status; 67 | 68 | status = sto->SetAttribute(sto, fgmap[fgcol]|bgmap[bgcol]); 69 | where("setattr fg %#x bg %#x -> %x", fgcol, bgcol, status); 70 | return status; 71 | } 72 | 73 | static EFI_STATUS 74 | setfg(unsigned char col) 75 | { 76 | fgcol = col; 77 | return setattr(); 78 | } 79 | 80 | static EFI_STATUS 81 | setbg(unsigned char col) 82 | { 83 | bgcol = col; 84 | return setattr(); 85 | } 86 | 87 | void 88 | mch_early_init(void) 89 | { 90 | // kill wdt 91 | gBS->SetWatchdogTimer (0, 0, 0, NULL); 92 | 93 | // don't buffer debug output 94 | setbuf(stderr, NULL); 95 | } 96 | 97 | int 98 | mch_init(void) 99 | { 100 | int fd; 101 | EFI_STATUS status; 102 | 103 | // init the console 104 | status = gBS->HandleProtocol(gST->ConsoleOutHandle, &gEfiSimpleTextOutProtocolGuid, (VOID**)&sto); 105 | if(EFI_ERROR(status)){ 106 | where("console init failed: %#x", status); 107 | exit(1); 108 | } 109 | 110 | fgcol = 7; 111 | bgcol = 0; 112 | setattr(); 113 | 114 | mch_get_shellsize(); 115 | 116 | //sto->Reset(sto, TRUE); 117 | sto->EnableCursor(sto, TRUE); 118 | sto->ClearScreen(sto); 119 | 120 | // we'll set nonblock on stdin so reading does not block 121 | fd = STDIN_FILENO; 122 | int flags = fcntl(fd, F_GETFL, 0); 123 | fcntl(fd, F_SETFL, flags | O_NONBLOCK); 124 | return -1; 125 | } 126 | 127 | void 128 | mch_exit(int code) 129 | { 130 | where("exit %d", code); 131 | exit(code); 132 | } 133 | 134 | void 135 | mch_suspend(void) 136 | { 137 | where(); 138 | } 139 | 140 | void 141 | mch_breakcheck(int force) 142 | { 143 | } 144 | 145 | void 146 | mch_hide(unsigned char *name) 147 | { 148 | } 149 | 150 | int 151 | mch_get_shellsize(void) 152 | { 153 | EFI_STATUS status; 154 | 155 | status = sto->QueryMode(sto, sto->Mode->Mode, &cols, &rows); 156 | if(EFI_ERROR(status)){ 157 | where("getting console size failed: %#x", status); 158 | exit(1); 159 | } 160 | 161 | Rows = rows; 162 | Columns = cols; 163 | 164 | return OK; 165 | } 166 | 167 | void 168 | mch_set_shellsize(void) 169 | { 170 | } 171 | 172 | void 173 | mch_new_shellsize(void) 174 | { 175 | } 176 | 177 | void 178 | mch_get_host_name(unsigned char *s, int len) 179 | { 180 | strncpy((char*)s, "efi", len-1); 181 | //gethostname((char*)s, (size_t)len); 182 | } 183 | 184 | long 185 | mch_get_pid(void) 186 | { 187 | return (long)getpid(); 188 | } 189 | 190 | unsigned char* 191 | mch_getenv(unsigned char *name) 192 | { 193 | return NULL; 194 | } 195 | 196 | int 197 | mch_has_wildcard(unsigned char *p) 198 | { 199 | where("p %s", p); 200 | for(; *p; MB_PTR_ADV(p)){ 201 | if(*p == '\\' && p[1] != NUL){ 202 | ++p; 203 | } else if(vim_strchr((char_u *)"*?[{`'$", *p) != NULL || 204 | (*p == '~' && p[1] != NUL)){ 205 | return TRUE; 206 | } 207 | } 208 | return FALSE; 209 | } 210 | 211 | int 212 | mch_has_exp_wildcard(unsigned char *p) 213 | { 214 | where("p %s", p); 215 | for (; *p; MB_PTR_ADV(p)){ 216 | if (*p == '\\' && p[1] != NUL) 217 | ++p; 218 | else if (vim_strchr((char_u *) "*?[{'", *p) != NULL) 219 | return TRUE; 220 | } 221 | return FALSE; 222 | } 223 | 224 | int 225 | mch_expandpath(void *gap /* garray_T* */, unsigned char *pat, int flags) 226 | { 227 | where("pat %s flags %#x", pat, flags); 228 | garray_T *ga = gap; 229 | (void)ga; 230 | return FAIL; 231 | } 232 | 233 | long 234 | mch_getperm(unsigned char *name) 235 | { 236 | struct stat st; 237 | if (stat((char*)name, &st) < 0) { 238 | return -1; 239 | } 240 | where("file `%s` mode %o", name, st.st_mode); 241 | 242 | // mask off uefi bits 243 | return st.st_mode & (S_IFMT | ALLPERMS); 244 | } 245 | 246 | int 247 | mch_setperm(unsigned char *name, long perm) 248 | { 249 | where("name `%s` mode %o", name, perm); 250 | return chmod((char*)name, (mode_t)perm) == 0 ? OK : FAIL; 251 | } 252 | 253 | int 254 | mch_nodetype(unsigned char *name) 255 | { 256 | struct stat st; 257 | if (stat((char*)name, &st) < 0) { 258 | return NODE_NORMAL; 259 | } 260 | if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode)) { 261 | return NODE_NORMAL; 262 | } 263 | return NODE_WRITABLE; 264 | } 265 | 266 | int 267 | mch_screenmode(unsigned char *arg) 268 | { 269 | where(); 270 | //EMSG(_(e_screenmode)); 271 | return FAIL; 272 | } 273 | 274 | int 275 | mch_check_win(int argc, char **argv) 276 | { 277 | return OK; 278 | } 279 | 280 | void 281 | mch_settitle(unsigned char *title, unsigned char *icon) 282 | { 283 | } 284 | 285 | void 286 | mch_restore_title(int which) 287 | { 288 | } 289 | 290 | int 291 | mch_can_restore_icon(void) 292 | { 293 | return FAIL; 294 | } 295 | 296 | int 297 | mch_can_restore_title(void) 298 | { 299 | return FAIL; 300 | } 301 | 302 | void 303 | mch_setmouse(int on) 304 | { 305 | } 306 | 307 | static int 308 | RealWaitForChar(int fd, long msec, int *_unused) 309 | { 310 | UINTN index; 311 | EFI_STATUS status; 312 | EFI_EVENT te; 313 | EFI_EVENT evs[2]; 314 | 315 | // just try uefi wait event 316 | if(msec < 0){ 317 | gBS->WaitForEvent(1, &gST->ConIn->WaitForKey, &index); 318 | return 1; 319 | } 320 | 321 | gBS->CreateEvent(EVT_TIMER, 0, NULL, NULL, &te); 322 | gBS->SetTimer(te, TimerRelative, msec * 10000); 323 | 324 | evs[0] = gST->ConIn->WaitForKey; 325 | evs[1] = te; 326 | 327 | status = gBS->WaitForEvent(2, evs, &index); 328 | if(EFI_ERROR(status)) 329 | return -1; 330 | 331 | // timeout? 332 | if(index == 1) 333 | return 0; 334 | 335 | return 1; 336 | } 337 | 338 | // -1 == forever 339 | // 0 == no block 340 | // n == timeout 341 | static int 342 | WaitForChar(long msec) 343 | { 344 | return RealWaitForChar(STDIN_FILENO, msec, NULL); 345 | } 346 | 347 | void 348 | mch_delay(long msec, int ignoreinput) 349 | { 350 | if(ignoreinput) 351 | usleep(msec*1000); 352 | else 353 | RealWaitForChar(STDIN_FILENO, msec, NULL); 354 | } 355 | 356 | int 357 | mch_inchar(unsigned char *buf, int maxlen, long wtime, int tb_change_cnt) 358 | { 359 | int len; 360 | 361 | where("wtime %d", wtime); 362 | 363 | if(wtime >= 0){ 364 | if(WaitForChar(wtime) == 0) 365 | return 0; 366 | } 367 | 368 | // -1, wait forever 369 | for(;;){ 370 | if(WaitForChar(-1) == 0) 371 | return 0; 372 | len = read(STDIN_FILENO, buf, maxlen/*maxlen*/); 373 | where("read `%.*s`", len, *buf); 374 | if(len > 0) 375 | return len; 376 | } 377 | } 378 | 379 | /* Read a number and return bytes consumed. */ 380 | static int 381 | scr_escape_number(char *p, int len, int *n) 382 | { 383 | int num; 384 | int chlen; 385 | 386 | if(len == 0){ 387 | return -1; 388 | } 389 | 390 | num = 0; 391 | chlen = 0; 392 | while(len && isdigit(*p)){ 393 | num = num * 10 + (*p - '0'); 394 | p++; 395 | len--; 396 | chlen++; 397 | } 398 | 399 | *n = num; 400 | return chlen; 401 | } 402 | 403 | static void 404 | fixops(int *operand) 405 | { 406 | if(operand[0] < 1) 407 | operand[0] = 1; 408 | } 409 | 410 | static void 411 | curset(int col, int row) 412 | { 413 | /* escape codes use 1-based cursor, uefi uses 0 */ 414 | where("curset %d %d", col-1, row-1); 415 | sto->SetCursorPosition(sto, col-1, row-1); 416 | } 417 | 418 | static void 419 | curdelta(int col, int row) 420 | { 421 | UINTN newcol, newrow; 422 | 423 | newcol = sto->Mode->CursorColumn + col; 424 | newrow = sto->Mode->CursorRow + row; 425 | where("curdelta %d %d", newcol, newrow); 426 | sto->SetCursorPosition(sto, newcol, newrow); 427 | } 428 | 429 | /* Handle escape sequence and return number of bytes consumed. */ 430 | static int 431 | scr_escape_sequence(char *p, int len) 432 | { 433 | UINTN scol, srow, color; 434 | int operand[10]; 435 | int noperand; 436 | int i; 437 | int chlen; 438 | 439 | if(len == 0){ 440 | return 0; 441 | } 442 | 443 | chlen = 0; 444 | 445 | 446 | memset(operand, 0, sizeof(operand)); 447 | i = scr_escape_number(p, len, &operand[0]); 448 | noperand = 1; 449 | p += i; 450 | len -= i; 451 | chlen += i; 452 | //where("\noperand[0] = %d operand[1] = %d operand[2] = %d look = %c",operand[0],operand[1],operand[2], *p); 453 | while(*p == ';' || *p == '?'){ 454 | p += 1; 455 | len -= 1; 456 | chlen += 1; 457 | if(noperand >= 10){ 458 | where("too many escape operands"); 459 | exit(1); 460 | } 461 | 462 | /* +1 to skip ;/? */ 463 | i = scr_escape_number(p, len, &operand[noperand]); 464 | noperand++; 465 | p += i; 466 | len -= i; 467 | chlen += i; 468 | } 469 | 470 | chlen += 1; 471 | switch(*p){ 472 | case 'J': /* clear screen */ 473 | sto->ClearScreen(sto); 474 | break; 475 | 476 | case 'C': /* cursor forward */ 477 | fixops(operand); 478 | curdelta(operand[0], 0); 479 | break; 480 | 481 | case 'H': /* cursor motion */ 482 | fixops(operand+1); 483 | curset(operand[1], operand[0]); 484 | break; 485 | 486 | case 'K': /* Clear in Line */ 487 | scol = sto->Mode->CursorColumn, srow = sto->Mode->CursorRow; 488 | switch(operand[0]){ 489 | case 2: /* whole line */ 490 | sto->SetCursorPosition(sto, 0, sto->Mode->CursorRow); 491 | for(i = 0; i < cols; i++) 492 | write(STDOUT_FILENO, " ", 1); 493 | break; 494 | case 1: /* start of line to pos */ 495 | sto->SetCursorPosition(sto, 0, sto->Mode->CursorRow); 496 | for(i = 0; i < scol; i++) 497 | write(STDOUT_FILENO, " ", 1); 498 | break; 499 | default: /* pos to eol */ 500 | for(i = 0; i < cols-scol-1; i++) 501 | write(STDOUT_FILENO, " ", 1); 502 | break; 503 | } 504 | sto->SetCursorPosition(sto, scol, srow); 505 | break; 506 | 507 | case 'm': /* mode */ 508 | i = operand[0]; 509 | if(i == 0){ 510 | setfg(7); 511 | setbg(0); 512 | } else if(i == 7){ 513 | /* swap fg/bg */ 514 | color = bgcol; 515 | bgcol = fgcol; 516 | fgcol = bgcol; 517 | setattr(); 518 | } else if(i >= 30 && i <= 37){ 519 | /* fg color */ 520 | setfg(i-30); 521 | } else if(i >= 40 && i <= 47){ 522 | /* bg color */ 523 | setbg(i-40); 524 | } else { 525 | where("scr_escape_sequence: unhandles mode sequence (p=%d)", i); 526 | } 527 | break; 528 | 529 | //case 'R': /* scroll region */ 530 | /* 531 | where("fix R"); 532 | scrollregion.min.y = n1; 533 | scrollregion.max.y = n2 + 1; 534 | */ 535 | break; 536 | 537 | //case 'V': /* scroll region vertical */ 538 | /* 539 | where("fix V"); 540 | scrollregion.min.x = n1; 541 | scrollregion.max.x = n2 + 1; 542 | */ 543 | break; 544 | 545 | //case 'K': /* clear to end of line */ 546 | /* 547 | where("fix K"); 548 | draw(screen, Rect(screen->clipr.min.x + curcol * fontsize.x, 549 | screen->clipr.min.y + currow * fontsize.y, 550 | screen->clipr.max.x, 551 | screen->clipr.min.y + (currow + 1) * fontsize.y), 552 | bgcolor, nil, ZP); 553 | break; 554 | */ 555 | 556 | case 'L': /* add new blank line */ 557 | p++; 558 | int nlines = 1; 559 | while(len >= 3 && p[0] == '\x1b' && p[1] == '[' && p[2] == 'L'){ 560 | nlines++; 561 | len -= 3; 562 | p += 3; 563 | chlen += 3; 564 | } 565 | for(i = 0; i < nlines; i++){ 566 | // bleg, \n side effects. 567 | mch_write((unsigned char*)"\n", 1); 568 | } 569 | break; 570 | 571 | default: 572 | /* TODO */ 573 | where("scr_escape_sequence: unhandled sequence (p=%c)", *p); 574 | exit(1); 575 | } 576 | 577 | return chlen; 578 | } 579 | 580 | void 581 | mch_write(unsigned char *_p, int _len) 582 | { 583 | char *p, buf[4096]; 584 | size_t len, n; 585 | 586 | if(_len > sizeof(buf)-1){ 587 | where("too much crap to write"); 588 | exit(1); 589 | } 590 | 591 | len = snprintf(buf, sizeof(buf), "%.*s", _len, _p); 592 | p = buf; 593 | 594 | where("output `%.*s`\n", len, p); 595 | 596 | while(len > 0){ 597 | /* 598 | fprintf(stdout, "%#x ", *p); 599 | if(isprint(*p)) 600 | fprintf(stdout, "%c\n", *p); 601 | else 602 | fprintf(stdout, "%o\n", *p); 603 | len--; 604 | p++; 605 | // */ 606 | /**/ 607 | n = strcspn((char*)p, "\a\b\033"); 608 | if(n != 0){ 609 | where("write `%.*s`\n", n, p); 610 | write(STDOUT_FILENO, p, n); 611 | len -= n; 612 | p += n; 613 | continue; 614 | } 615 | 616 | switch(*p){ 617 | case '\a': 618 | len--, p++; 619 | break; 620 | case '\b': 621 | len--, p++; 622 | curdelta(-1, 0); 623 | write(STDOUT_FILENO, " ", 1); 624 | curdelta(-1, 0); 625 | break; 626 | case '\n': 627 | len--, p++; 628 | write(STDOUT_FILENO, p, 1); 629 | break; 630 | case '\r': 631 | len--, p++; 632 | write(STDOUT_FILENO, p, 1); 633 | break; 634 | case '\033': 635 | if(len < 3 || p[1] != '['){ 636 | where("bad escape data: %s", p); 637 | exit(1); 638 | } 639 | 640 | n = 2; 641 | n += scr_escape_sequence((char*)p+2, len-2); 642 | where("escape `%.*s`\n", n, p); 643 | len -= n; 644 | p += n; 645 | break; 646 | default: 647 | where("whack attack %#x", *p); 648 | exit(1); 649 | } 650 | // */ 651 | } 652 | } 653 | 654 | int 655 | mch_char_avail(void) 656 | { 657 | return WaitForChar(0); 658 | } 659 | 660 | int 661 | mch_rename(const char *src, const char *dest) 662 | { 663 | struct stat st; 664 | int rv; 665 | 666 | where("src %s dest %s", src, dest); 667 | 668 | rv = stat(dest, &st); 669 | if(rv >= 0){ 670 | where("file `%s` exists", dest); 671 | return -1; 672 | } 673 | 674 | rv = rename(src, dest); 675 | if(rv != 0){ 676 | where("rename `%s` -> `%s` failed: %d %s", src, dest, errno, strerror(errno)); 677 | return -1; 678 | } 679 | 680 | return 0; 681 | } 682 | 683 | int 684 | mch_remove(unsigned char *name) 685 | { 686 | return remove((char*)name); 687 | } 688 | 689 | int 690 | mch_isdir(unsigned char *name) 691 | { 692 | struct stat st; 693 | if (stat((char*)name, &st) != 0) { 694 | return FALSE; 695 | } 696 | return S_ISDIR(st.st_mode) ? TRUE : FALSE; 697 | } 698 | 699 | int 700 | mch_dirname(unsigned char *buf, int len) 701 | { 702 | return (getcwd((char*)buf, len) ? OK : FAIL); 703 | } 704 | 705 | int 706 | mch_chdir(char *path) 707 | { 708 | return chdir(path); 709 | } 710 | 711 | int 712 | mch_isFullName(unsigned char *fname) 713 | { 714 | // e.g. fs0:\foo.txt 715 | if (strstr((char*)fname, ":\\") != NULL) 716 | return TRUE; 717 | 718 | return FALSE; 719 | } 720 | 721 | int 722 | mch_FullName(unsigned char *fname, unsigned char *buf, int len, int force) 723 | { 724 | char path[PATH_MAX]; 725 | 726 | where("fname `%s`", fname); 727 | 728 | if(realpath((char*)fname, path) == NULL) 729 | return FAIL; 730 | 731 | where("expand `%s`", path); 732 | 733 | strncpy((char*)buf, (char*)path, len-1); 734 | if(len > 0) 735 | buf[len-1] = '\0'; 736 | 737 | return OK; 738 | } 739 | 740 | int 741 | mch_input_isatty(void) 742 | { 743 | return isatty(STDIN_FILENO); 744 | } 745 | 746 | void 747 | mch_settmode(int mode) 748 | { 749 | static int first = TRUE; 750 | static struct termios told; 751 | struct termios tnew; 752 | 753 | if(first){ 754 | first = FALSE; 755 | tcgetattr(STDIN_FILENO, &told); 756 | } 757 | 758 | tnew = told; 759 | 760 | where("mode %d", mode); 761 | 762 | switch(mode){ 763 | case TMODE_COOK: 764 | break; 765 | case TMODE_SLEEP: 766 | tnew.c_lflag &= ~(ECHO); 767 | break; 768 | case TMODE_RAW: 769 | tnew.c_iflag &= ~ICRNL; 770 | tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE | IEXTEN); 771 | //tnew.c_oflag &= ~ONLCR; 772 | tnew.c_oflag |= ONLRET; 773 | tnew.c_cc[VMIN] = 1; 774 | tnew.c_cc[VTIME] = 0; 775 | } 776 | 777 | tcsetattr(STDIN_FILENO, TCSANOW, &tnew); 778 | } 779 | 780 | int 781 | mch_can_exe(unsigned char *name, unsigned char **path, int use_path) 782 | { 783 | return -1; 784 | } 785 | 786 | int 787 | mch_call_shell(unsigned char *cmd, int options) 788 | { 789 | return -1; 790 | } 791 | 792 | int 793 | mch_get_user_name(unsigned char *s, int len) 794 | { 795 | vim_strncpy(s, (unsigned char*)"none", len-1); 796 | return OK; 797 | } 798 | 799 | char **environ = NULL; 800 | 801 | int 802 | putenv(const char *string) 803 | { 804 | errno = ENOSYS; 805 | return -1; 806 | } 807 | 808 | void 809 | slash_adjust(unsigned char *p) 810 | { 811 | if(path_with_url(p)) 812 | return; 813 | while(*p){ 814 | if(*p == psepcN) 815 | *p = psepc; 816 | MB_PTR_ADV(p); 817 | } 818 | } 819 | 820 | /* pathdef.c */ 821 | #include "vim.h" 822 | char_u *default_vim_dir = (char_u *)"fs0:\\vim"; 823 | char_u *default_vimruntime_dir = (char_u *)"fs0:\\vim\\vimfiles"; 824 | char_u *all_cflags = (char_u *)"you don't want to know"; 825 | char_u *all_lflags = (char_u *)"you don't want to know"; 826 | char_u *compiled_user = (char_u *)"none"; 827 | char_u *compiled_sys = (char_u *)"none"; 828 | 829 | -------------------------------------------------------------------------------- /vim.dec: -------------------------------------------------------------------------------- 1 | [Defines] 2 | DEC_SPECIFICATION = 1.25 3 | PACKAGE_NAME = vim 4 | PACKAGE_GUID = d499534e-c438-40e3-94c8-a24be1f3bd4a 5 | PACKAGE_VERSION = 1.0 6 | 7 | [Includes.common] 8 | include 9 | vim/src/proto 10 | 11 | -------------------------------------------------------------------------------- /vim.dsc: -------------------------------------------------------------------------------- 1 | [Components] 2 | vim.inf 3 | 4 | [PcdsFixedAtBuild] 5 | !if $(TARGET) == "DEBUG" 6 | DEFINE DEBUG_PRINT_ERROR_LEVEL = 0x80000040 7 | DEFINE DEBUG_PROPERTY_MASK = 0xFF 8 | !endif 9 | 10 | !include edk2-libc/AppPkg/AppPkg.dsc 11 | 12 | [LibraryClasses] 13 | !if $(TARGET) == "DEBUG" 14 | DEFINE DEBUG_ENABLE_OUTPUT = TRUE 15 | SerialPortLib|PcAtChipsetPkg/Library/SerialIoLib/SerialIoLib.inf 16 | DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf 17 | DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf 18 | !endif 19 | 20 | -------------------------------------------------------------------------------- /vim.inf: -------------------------------------------------------------------------------- 1 | [Defines] 2 | INF_VERSION = 1.25 3 | BASE_NAME = vim 4 | FILE_GUID = d499534e-c438-40e3-94c8-a24be1f3bd4a 5 | MODULE_TYPE = UEFI_APPLICATION 6 | VERSION_STRING = 1.0 7 | ENTRY_POINT = ShellCEntryLib 8 | 9 | [Sources] 10 | src/efivim.c 11 | vim/src/buffer.c 12 | vim/src/blowfish.c 13 | vim/src/charset.c 14 | vim/src/crypt.c 15 | vim/src/crypt_zip.c 16 | vim/src/dict.c 17 | vim/src/diff.c 18 | vim/src/digraph.c 19 | vim/src/edit.c 20 | vim/src/eval.c 21 | vim/src/evalfunc.c 22 | vim/src/ex_cmds.c 23 | vim/src/ex_cmds2.c 24 | vim/src/ex_docmd.c 25 | vim/src/ex_eval.c 26 | vim/src/ex_getln.c 27 | vim/src/fileio.c 28 | vim/src/fold.c 29 | vim/src/getchar.c 30 | vim/src/hardcopy.c 31 | vim/src/hashtab.c 32 | vim/src/if_cscope.c 33 | vim/src/if_lua.c 34 | vim/src/if_xcmdsrv.c 35 | vim/src/list.c 36 | vim/src/mark.c 37 | vim/src/memline.c 38 | vim/src/menu.c 39 | vim/src/message.c 40 | vim/src/misc1.c 41 | vim/src/misc2.c 42 | vim/src/move.c 43 | vim/src/mbyte.c 44 | vim/src/normal.c 45 | vim/src/ops.c 46 | vim/src/option.c 47 | vim/src/popupmnu.c 48 | vim/src/quickfix.c 49 | vim/src/regexp.c 50 | vim/src/screen.c 51 | vim/src/search.c 52 | vim/src/sha256.c 53 | vim/src/spell.c 54 | vim/src/spellfile.c 55 | vim/src/syntax.c 56 | vim/src/tag.c 57 | vim/src/term.c 58 | vim/src/ui.c 59 | vim/src/undo.c 60 | vim/src/window.c 61 | vim/src/json.c 62 | vim/src/main.c 63 | vim/src/memfile.c 64 | vim/src/userfunc.c 65 | vim/src/version.c 66 | 67 | [Packages] 68 | StdLib/StdLib.dec 69 | MdePkg/MdePkg.dec 70 | 71 | vim.dec 72 | 73 | [LibraryClasses] 74 | UefiLib 75 | LibC 76 | LibString 77 | LibStdio 78 | LibGdtoa 79 | LibMath 80 | LibWchar 81 | LibGen 82 | LibTime 83 | LibNetUtil 84 | DevMedia 85 | LuaLib 86 | 87 | [BuildOptions] 88 | GCC:*_*_X64_CC_FLAGS == -g -fshort-wchar -fno-strict-aliasing -Wall -Werror -Wno-switch -Wno-array-bounds -ffunction-sections -fdata-sections -include AutoGen.h -fno-common -DSTRING_ARRAY_NAME=vimStrings -m64 -fno-stack-protector "-DEFIAPI=__attribute__((ms_abi))" -DNO_BUILTIN_VA_FUNCS -mno-red-zone -Wno-address -mcmodel=small -fpie -fno-asynchronous-unwind-tables -Wno-address -Wno-unused-but-set-variable -fno-builtin -include include/efivim.h -DFEAT_NORMAL -DFEAT_BROWSE -DFEAT_LUA -DFEAT_MBYTE -DHAVE_MEMMOVE -DHAVE_PUTENV -DHAVE_QSORT -DHAVE_CONFIG_H -DVIM_SIZEOF_INT=4 -DSPACE_IN_FILENAME -DBACKSLASH_IN_FILENAME -DHAVE_ST_MODE -DCASE_INSENSITIVE_FILENAME -DDEFAULT_TERM='(char_u*)"ansi"' 89 | 90 | --------------------------------------------------------------------------------