From d2844807a60e3b54a4d9d28c9ce2e8e9ba01d8a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Polg=C3=A1r?= Date: Fri, 22 Sep 2023 20:22:21 +0200 Subject: [PATCH 01/17] Very basic word completion, subword search in progess --- config/default.focus-config | 4 + modules/EGL/module.jai | 302 ++++++++++++++++++++++++++++++++++++ src/draw.jai | 41 +++++ src/editors.jai | 226 +++++++++++++++++++++++++++ src/keymap.jai | 3 + src/utils.jai | 22 +++ 6 files changed, 598 insertions(+) create mode 100644 modules/EGL/module.jai diff --git a/config/default.focus-config b/config/default.focus-config index a119db5b7..d936e00e3 100644 --- a/config/default.focus-config +++ b/config/default.focus-config @@ -88,6 +88,10 @@ Ctrl-K delete_to_end_of_line Ctrl-Shift-Delete delete_to_end_of_line Ctrl-Shift-Backspace delete_to_start_of_line +Ctrl-E word_completion_next +Ctrl-Q word_completion_previous +Ctrl-R word_completion_subword + Alt-ArrowUp move_selected_lines_up Alt-ArrowDown move_selected_lines_down diff --git a/modules/EGL/module.jai b/modules/EGL/module.jai new file mode 100644 index 000000000..b9ab49cdd --- /dev/null +++ b/modules/EGL/module.jai @@ -0,0 +1,302 @@ +EGLDisplay :: *_EGLDisplay; +EGLConfig :: *_EGLConfig; +EGLSurface :: *_EGLSurface; +EGLContext :: *_EGLContext; + +EGLClientBuffer :: *_EGLClientBuffer; + +EGLSync :: *_EGLSync; +EGLImage :: *_EGLImage; + +EGLNativePixmapType :: *void; +EGLNativeDisplayType :: *void; +EGLNativeWindowType :: *void; + +/* EGL 1.0.1 */ +EGL_ALPHA_SIZE : s32 : 0x3021; +EGL_BAD_ACCESS : s32 : 0x3002; +EGL_BAD_ALLOC : s32 : 0x3003; +EGL_BAD_ATTRIBUTE : s32 : 0x3004; +EGL_BAD_CONFIG : s32 : 0x3005; +EGL_BAD_CONTEXT : s32 : 0x3006; +EGL_BAD_CURRENT_SURFACE : s32 : 0x3007; +EGL_BAD_DISPLAY : s32 : 0x3008; +EGL_BAD_MATCH : s32 : 0x3009; +EGL_BAD_NATIVE_PIXMAP : s32 : 0x300A; +EGL_BAD_NATIVE_WINDOW : s32 : 0x300B; +EGL_BAD_PARAMETER : s32 : 0x300C; +EGL_BAD_SURFACE : s32 : 0x300D; +EGL_BLUE_SIZE : s32 : 0x3022; +EGL_BUFFER_SIZE : s32 : 0x3020; +EGL_CONFIG_CAVEAT : s32 : 0x3027; +EGL_CONFIG_ID : s32 : 0x3028; +EGL_CORE_NATIVE_ENGINE : s32 : 0x305B; +EGL_DEPTH_SIZE : s32 : 0x3025; +EGL_DONT_CARE : s32 : -1; +EGL_DRAW : s32 : 0x3059; +EGL_EXTENSIONS : s32 : 0x3055; +EGL_FALSE : s32 : 0; +EGL_GREEN_SIZE : s32 : 0x3023; +EGL_HEIGHT : s32 : 0x3056; +EGL_LARGEST_PBUFFER : s32 : 0x3058; +EGL_LEVEL : s32 : 0x3029; +EGL_MAX_PBUFFER_HEIGHT : s32 : 0x302A; +EGL_MAX_PBUFFER_PIXELS : s32 : 0x302B; +EGL_MAX_PBUFFER_WIDTH : s32 : 0x302C; +EGL_NATIVE_RENDERABLE : s32 : 0x302D; +EGL_NATIVE_VISUAL_ID : s32 : 0x302E; +EGL_NATIVE_VISUAL_TYPE : s32 : 0x302F; +EGL_NONE : s32 : 0x3038; +EGL_NON_CONFORMANT_CONFIG : s32 : 0x3051; +EGL_NOT_INITIALIZED : s32 : 0x3001; +EGL_NO_CONTEXT :: cast(EGLContext) null; +EGL_NO_DISPLAY :: cast(EGLDisplay) null; +EGL_NO_SURFACE :: cast(EGLSurface) null; +EGL_PBUFFER_BIT : s32 : 0x0001; +EGL_PIXMAP_BIT : s32 : 0x0002; +EGL_READ : s32 : 0x305A; +EGL_RED_SIZE : s32 : 0x3024; +EGL_SAMPLES : s32 : 0x3031; +EGL_SAMPLE_BUFFERS : s32 : 0x3032; +EGL_SLOW_CONFIG : s32 : 0x3050; +EGL_STENCIL_SIZE : s32 : 0x3026; +EGL_SUCCESS : s32 : 0x3000; +EGL_SURFACE_TYPE : s32 : 0x3033; +EGL_TRANSPARENT_BLUE_VALUE : s32 : 0x3035; +EGL_TRANSPARENT_GREEN_VALUE : s32 : 0x3036; +EGL_TRANSPARENT_RED_VALUE : s32 : 0x3037; +EGL_TRANSPARENT_RGB : s32 : 0x3052; +EGL_TRANSPARENT_TYPE : s32 : 0x3034; +EGL_TRUE : s32 : 1; +EGL_VENDOR : s32 : 0x3053; +EGL_VERSION : s32 : 0x3054; +EGL_WIDTH : s32 : 0x3057; +EGL_WINDOW_BIT : s32 : 0x0004; + +eglChooseConfig :: (dpy: EGLDisplay, attrib_list: *s32, configs: *EGLConfig, config_size: s32, num_config: *s32) -> s32 #foreign libEGL; +eglCopyBuffers :: (dpy: EGLDisplay, surface: EGLSurface, target: EGLNativePixmapType) -> s32 #foreign libEGL; +eglCreateContext :: (dpy: EGLDisplay, config: EGLConfig, share_context: EGLContext, attrib_list: *s32) -> EGLContext #foreign libEGL; +eglCreatePbufferSurface :: (dpy: EGLDisplay, config: EGLConfig, attrib_list: *s32) -> EGLSurface #foreign libEGL; +eglCreatePixmapSurface :: (dpy: EGLDisplay, config: EGLConfig, pixmap: EGLNativePixmapType, attrib_list: *s32) -> EGLSurface #foreign libEGL; +eglCreateWindowSurface :: (dpy: EGLDisplay, config: EGLConfig, win: EGLNativeWindowType, attrib_list: *s32) -> EGLSurface #foreign libEGL; +eglDestroyContext :: (dpy: EGLDisplay, ctx: EGLContext) -> s32 #foreign libEGL; +eglDestroySurface :: (dpy: EGLDisplay, surface: EGLSurface) -> s32 #foreign libEGL; +eglGetConfigAttrib :: (dpy: EGLDisplay, config: EGLConfig, attribute: s32, value: *s32) -> s32 #foreign libEGL; +eglGetConfigs :: (dpy: EGLDisplay, configs: *EGLConfig, config_size: s32, num_config: *s32) -> s32 #foreign libEGL; +eglGetCurrentDisplay :: () -> EGLDisplay #foreign libEGL; +eglGetCurrentSurface :: (readdraw: s32) -> EGLSurface #foreign libEGL; +eglGetDisplay :: (display_id: EGLNativeDisplayType) -> EGLDisplay #foreign libEGL; +eglGetError :: () -> s32 #foreign libEGL; +eglGetProcAddress :: (procname: *u8) -> *void #foreign libEGL; +eglInitialize :: (dpy: EGLDisplay, major: *s32, minor: *s32) -> s32 #foreign libEGL; +eglMakeCurrent :: (dpy: EGLDisplay, draw: EGLSurface, read: EGLSurface, ctx: EGLContext) -> s32 #foreign libEGL; +eglQueryContext :: (dpy: EGLDisplay, ctx: EGLContext, attribute: s32, value: *s32) -> s32 #foreign libEGL; +eglQueryString :: (dpy: EGLDisplay, name: s32) -> *u8 #foreign libEGL; +eglQuerySurface :: (dpy: EGLDisplay, surface: EGLSurface, attribute: s32, value: *s32) -> s32 #foreign libEGL; +eglSwapBuffers :: (dpy: EGLDisplay, surface: EGLSurface) -> s32 #foreign libEGL; +eglTerminate :: (dpy: EGLDisplay) -> s32 #foreign libEGL; +eglWaitGL :: () -> s32 #foreign libEGL; +eglWaitNative :: (engine: s32) -> s32 #foreign libEGL; + +/* EGL 1.1 */ +EGL_BACK_BUFFER : s32 : 0x3084; +EGL_BIND_TO_TEXTURE_RGB : s32 : 0x3039; +EGL_BIND_TO_TEXTURE_RGBA : s32 : 0x303A; +EGL_CONTEXT_LOST : s32 : 0x300E; +EGL_MIN_SWAP_INTERVAL : s32 : 0x303B; +EGL_MAX_SWAP_INTERVAL : s32 : 0x303C; +EGL_MIPMAP_TEXTURE : s32 : 0x3082; +EGL_MIPMAP_LEVEL : s32 : 0x3083; +EGL_NO_TEXTURE : s32 : 0x305C; +EGL_TEXTURE_2D : s32 : 0x305F; +EGL_TEXTURE_FORMAT : s32 : 0x3080; +EGL_TEXTURE_RGB : s32 : 0x305D; +EGL_TEXTURE_RGBA : s32 : 0x305E; +EGL_TEXTURE_TARGET : s32 : 0x3081; + +eglBindTexImage :: (dpy: EGLDisplay, surface: EGLSurface, buffer: s32) -> s32 #foreign libEGL; +eglReleaseTexImage :: (dpy: EGLDisplay, surface: EGLSurface, buffer: s32) -> s32 #foreign libEGL; +eglSurfaceAttrib :: (dpy: EGLDisplay, surface: EGLSurface, attribute: s32, value: s32) -> s32 #foreign libEGL; +eglSwapInterval :: (dpy: EGLDisplay, interval: s32) -> s32 #foreign libEGL; + +/* EGL 1.2 */ +EGL_ALPHA_FORMAT : s32 : 0x3088; +EGL_ALPHA_FORMAT_NONPRE : s32 : 0x308B; +EGL_ALPHA_FORMAT_PRE : s32 : 0x308C; +EGL_ALPHA_MASK_SIZE : s32 : 0x303E; +EGL_BUFFER_PRESERVED : s32 : 0x3094; +EGL_BUFFER_DESTROYED : s32 : 0x3095; +EGL_CLIENT_APIS : s32 : 0x308D; +EGL_COLORSPACE : s32 : 0x3087; +EGL_COLORSPACE_sRGB : s32 : 0x3089; +EGL_COLORSPACE_LINEAR : s32 : 0x308A; +EGL_COLOR_BUFFER_TYPE : s32 : 0x303F; +EGL_CONTEXT_CLIENT_TYPE : s32 : 0x3097; +EGL_DISPLAY_SCALING : s32 : 10000; +EGL_HORIZONTAL_RESOLUTION : s32 : 0x3090; +EGL_LUMINANCE_BUFFER : s32 : 0x308F; +EGL_LUMINANCE_SIZE : s32 : 0x303D; +EGL_OPENGL_ES_BIT : s32 : 0x0001; +EGL_OPENVG_BIT : s32 : 0x0002; +EGL_OPENGL_ES_API : s32 : 0x30A0; +EGL_OPENVG_API : s32 : 0x30A1; +EGL_OPENVG_IMAGE : s32 : 0x3096; +EGL_PIXEL_ASPECT_RATIO : s32 : 0x3092; +EGL_RENDERABLE_TYPE : s32 : 0x3040; +EGL_RENDER_BUFFER : s32 : 0x3086; +EGL_RGB_BUFFER : s32 : 0x308E; +EGL_SINGLE_BUFFER : s32 : 0x3085; +EGL_SWAP_BEHAVIOR : s32 : 0x3093; +EGL_UNKNOWN : s32 : -1; +EGL_VERTICAL_RESOLUTION : s32 : 0x3091; + +eglBindAPI :: (api: s32) -> s32 #foreign libEGL; +eglQueryAPI :: () -> u32 #foreign libEGL; +eglCreatePbufferFromClientBuffer :: (dpy: EGLDisplay, buftype: u32, buffer: EGLClientBuffer, config: EGLConfig, attrib_list: *s32) -> EGLSurface #foreign libEGL; +eglReleaseThread :: () -> s32 #foreign libEGL; +eglWaitClient :: () -> s32 #foreign libEGL; + +/* EGL 1.3 */ +EGL_CONFORMANT : s32 : 0x3042; +EGL_CONTEXT_CLIENT_VERSION : s32 : 0x3098; +EGL_MATCH_NATIVE_PIXMAP : s32 : 0x3041; +EGL_OPENGL_ES2_BIT : s32 : 0x0004; +EGL_VG_ALPHA_FORMAT : s32 : 0x3088; +EGL_VG_ALPHA_FORMAT_NONPRE : s32 : 0x308B; +EGL_VG_ALPHA_FORMAT_PRE : s32 : 0x308C; +EGL_VG_ALPHA_FORMAT_PRE_BIT : s32 : 0x0040; +EGL_VG_COLORSPACE : s32 : 0x3087; +EGL_VG_COLORSPACE_sRGB : s32 : 0x3089; +EGL_VG_COLORSPACE_LINEAR : s32 : 0x308A; +EGL_VG_COLORSPACE_LINEAR_BIT : s32 : 0x0020; + +/* EGL 1.4 */ +EGL_DEFAULT_DISPLAY :: cast(EGLNativeDisplayType) null; +EGL_MULTISAMPLE_RESOLVE_BOX_BIT : s32 : 0x0200; +EGL_MULTISAMPLE_RESOLVE : s32 : 0x3099; +EGL_MULTISAMPLE_RESOLVE_DEFAULT : s32 : 0x309A; +EGL_MULTISAMPLE_RESOLVE_BOX : s32 : 0x309B; +EGL_OPENGL_API : s32 : 0x30A2; +EGL_OPENGL_BIT : s32 : 0x0008; +EGL_SWAP_BEHAVIOR_PRESERVED_BIT : s32 : 0x0400; + +/* EGL 1.5 */ +EGL_CONTEXT_MAJOR_VERSION : s32 : 0x3098; +EGL_CONTEXT_MINOR_VERSION : s32 : 0x30FB; +EGL_CONTEXT_OPENGL_PROFILE_MASK : s32 : 0x30FD; +EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY : s32 : 0x31BD; +EGL_NO_RESET_NOTIFICATION : s32 : 0x31BE; +EGL_LOSE_CONTEXT_ON_RESET : s32 : 0x31BF; +EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT : s32 : 0x00000001; +EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT : s32 : 0x00000002; +EGL_CONTEXT_OPENGL_DEBUG : s32 : 0x31B0; +EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE : s32 : 0x31B1; +EGL_CONTEXT_OPENGL_ROBUST_ACCESS : s32 : 0x31B2; +EGL_OPENGL_ES3_BIT : s32 : 0x00000040; +EGL_CL_EVENT_HANDLE : s32 : 0x309C; +EGL_SYNC_CL_EVENT : s32 : 0x30FE; +EGL_SYNC_CL_EVENT_COMPLETE : s32 : 0x30FF; +EGL_SYNC_PRIOR_COMMANDS_COMPLETE : s32 : 0x30F0; +EGL_SYNC_TYPE : s32 : 0x30F7; +EGL_SYNC_STATUS : s32 : 0x30F1; +EGL_SYNC_CONDITION : s32 : 0x30F8; +EGL_SIGNALED : s32 : 0x30F2; +EGL_UNSIGNALED : s32 : 0x30F3; +EGL_SYNC_FLUSH_COMMANDS_BIT : s32 : 0x0001; +EGL_FOREVER :: cast(u64) 0xFFFFFFFFFFFFFFFF; +EGL_TIMEOUT_EXPIRED : s32 : 0x30F5; +EGL_CONDITION_SATISFIED : s32 : 0x30F6; +EGL_NO_SYNC :: cast(EGLSync) null; +EGL_SYNC_FENCE : s32 : 0x30F9; +EGL_GL_COLORSPACE : s32 : 0x309D; +EGL_GL_COLORSPACE_SRGB : s32 : 0x3089; +EGL_GL_COLORSPACE_LINEAR : s32 : 0x308A; +EGL_GL_RENDERBUFFER : s32 : 0x30B9; +EGL_GL_TEXTURE_2D : s32 : 0x30B1; +EGL_GL_TEXTURE_LEVEL : s32 : 0x30BC; +EGL_GL_TEXTURE_3D : s32 : 0x30B2; +EGL_GL_TEXTURE_ZOFFSET : s32 : 0x30BD; +EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X : s32 : 0x30B3; +EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X : s32 : 0x30B4; +EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y : s32 : 0x30B5; +EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y : s32 : 0x30B6; +EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z : s32 : 0x30B7; +EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z : s32 : 0x30B8; +EGL_IMAGE_PRESERVED : s32 : 0x30D2; +EGL_NO_IMAGE :: cast(EGLImage) null; + +eglCreateSync :: (dpy: EGLDisplay, type: u32, attrib_list: *s64) -> EGLSync #foreign libEGL; +eglDestroySync :: (dpy: EGLDisplay, sync: EGLSync) -> s32 #foreign libEGL; +eglClientWaitSync :: (dpy: EGLDisplay, sync: EGLSync, flags: s32, timeout: u64) -> s32 #foreign libEGL; +eglGetSyncAttrib :: (dpy: EGLDisplay, sync: EGLSync, attribute: s32, value: s64) -> s32 #foreign libEGL; +eglCreateImage :: (dpy: EGLDisplay, ctx: EGLContext, target: u32, buffer: EGLClientBuffer, attrib_list: *s64) -> EGLImage #foreign libEGL; +eglDestroyImage :: (dpy: EGLDisplay, image: EGLImage) -> s32 #foreign libEGL; +eglGetPlatformDisplay :: (platform: u32, native_display: *void, attrib_list: *s64) -> EGLDisplay #foreign libEGL; +eglCreatePlatformWindowSurface :: (dpy: EGLDisplay, config: EGLConfig, native_window: *void, attrib_list: *s64) -> EGLSurface #foreign libEGL; +eglCreatePlatformPixmapSurface :: (dpy: EGLDisplay, config: EGLConfig, native_pixmap: *void, attrib_list: *s64) -> EGLSurface #foreign libEGL; +eglWaitSync :: (dpy: EGLDisplay, sync: EGLSync, flags: s32) -> s32 #foreign libEGL; + +egl_create_context :: (native_display: EGLNativeDisplayType, major_version := 0, minor_version := 0, + compatibility := false, debug := false) -> EGLDisplay, EGLContext, EGLConfig +{ + n: s32; + major: s32; + minor: s32; + + egl_dpy := eglGetDisplay(native_display); + eglInitialize(egl_dpy, *major, *minor); + eglBindAPI(EGL_OPENGL_API); + + config_attribs : []s32 = .[ + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + // EGL_ALPHA_SIZE, 8, // this makes the entire window translucent + EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, + EGL_NONE + ]; + egl_cnf: EGLConfig; + eglChooseConfig(egl_dpy, config_attribs.data, *egl_cnf, 1, *n); + + context_attribs: [9]s32; + attr_count := 0; + + if major_version > 0 { + context_attribs[attr_count + 0] = EGL_CONTEXT_MAJOR_VERSION; + context_attribs[attr_count + 1] = xx major_version; + context_attribs[attr_count + 2] = EGL_CONTEXT_MINOR_VERSION; + context_attribs[attr_count + 3] = xx minor_version; + attr_count += 4; + } + + context_attribs[attr_count + 0] = EGL_CONTEXT_OPENGL_PROFILE_MASK; + if compatibility context_attribs[attr_count + 1] = EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT; + else context_attribs[attr_count + 1] = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT; + attr_count += 2; + + if debug { + context_attribs[attr_count + 0] = EGL_CONTEXT_OPENGL_DEBUG; + context_attribs[attr_count + 1] = EGL_TRUE; + attr_count += 2; + } + + context_attribs[attr_count] = EGL_NONE; + + egl_ctx := eglCreateContext(egl_dpy, egl_cnf, EGL_NO_CONTEXT, context_attribs.data); + + return egl_dpy, egl_ctx, egl_cnf; +} + +#scope_file +_EGLDisplay :: struct {} +_EGLConfig :: struct {} +_EGLSurface :: struct {} +_EGLContext :: struct {} + +_EGLClientBuffer :: struct {} + +_EGLSync :: struct {} +_EGLImage :: struct {} + +libEGL :: #system_library "libEGL"; diff --git a/src/draw.jai b/src/draw.jai index b62e56c57..1ffafab08 100644 --- a/src/draw.jai +++ b/src/draw.jai @@ -1046,6 +1046,47 @@ draw_editor :: (editor_id: s64, main_area: Rect, footer_height: float, ui_id: Ui } } + // Draw word completion + if editor_is_active && word_complete.results.count { + mm := min(word_complete.results.count, WORD_COMPLETION_MAX_RESULTS); + + padding := floor(10 * dpi_scale); + item_delta_scaler := (line_height + 5) * dpi_scale; + cursor := cursors[0]; + cursor_screen_pos := get_cursor_screen_pos(text_origin, cursor_coords[0].pos); + + max_char := 0; + for word_complete.results { if it.word.count > max_char max_char = it.word.count; } + rect_w := (max_char * char_x_advance) + (padding * 2); + rect_h := mm * (item_delta_scaler) + padding; + + rect_top := cursor_screen_pos.y - rect_h; + rect_left := cursor_screen_pos.x + padding; + + if rect_top < 0 then rect_top = cursor_screen_pos.y + padding; + if rect_left + rect_w + padding > main_area.w + main_area.x { + rect_left = (main_area.w + main_area.x) - (rect_w + padding); + } + + rect := make_rect(rect_left, rect_top, rect_w, rect_h); + draw_rounded_rect(rect, Colors.BACKGROUND_DARK, radius = rounding_radius_small, set_shader = true); + + i := 0; + for word_complete.scroll_top..mm+word_complete.scroll_top-1 { + if it == word_complete.results.count then break; + item_left := rect_left + padding; + item_top := (rect_top + rect_h) - (item_delta_scaler * (i + 1)); + item_color := ifx (it % word_complete.results.count) == word_complete.selected_result_index + then Colors.CODE_OPERATION + else Colors.CODE_DEFAULT + + Simp.prepare_text(font, word_complete.results[it].word); + Simp.draw_prepared_text(font, cast(s64) item_left, cast(s64) item_top, item_color); + + i+=1; + } + } + // Draw search bar if active_global_widget != .editors then search_bar.active = false; diff --git a/src/editors.jai b/src/editors.jai index de0319319..3f398d306 100644 --- a/src/editors.jai +++ b/src/editors.jai @@ -139,6 +139,9 @@ active_editor_handle_event :: (event: Input.Event, action: Action_Editors) -> ha keep_selection := false; enabled_whole_words := false; + word_complete.should_abort = true; + defer { if word_complete.should_abort && word_complete.active then word_complete_abort(); } + handled := true; if action == { @@ -251,6 +254,10 @@ active_editor_handle_event :: (event: Input.Event, action: Action_Editors) -> ha case .delete_to_start_of_line; delete_to_start_of_line (editor, buffer); case .delete_to_end_of_line; delete_to_end_of_line (editor, buffer); + case .word_completion_next; word_completion(); + case .word_completion_previous; word_completion(forwards = false); + case .word_completion_subword; word_completion(search_for_subwords = true); + case; return false; } } @@ -3114,8 +3121,227 @@ free_editor :: (using editor: *Editor) { array_reset(*wrapped_line_starts); } +// @CleanUp: +word_completion :: (forwards := true, search_for_subwords := false) { + word_complete.should_abort = false; + + // @Todo: Disabled temporary + // context.underscore_is_part_of_word = !word_complete.search_for_subwords; + // defer context.underscore_is_part_of_word = true; + + // if !word_complete.active { + // word_complete.search_for_subwords = search_for_subwords; + // context.underscore_is_part_of_word = !search_for_subwords; + // } + + if !word_complete.active { + word_complete.active = true; + word_complete_search(); + + if word_complete.results.count == 0 { + word_complete.active = false; + return; + } + } + + if forwards word_completion_next(); + else word_completion_previous(); +} + +word_completion_next :: () { + using word_complete; + + selected_result_index = (selected_result_index + 1) % results.count; + + start := scroll_top; + end := start + WORD_COMPLETION_MAX_RESULTS; + + if selected_result_index+1 > end { + scroll_top += 1; + } + + word_complete_apply(); +} + +word_completion_previous :: () { + using word_complete; + + if selected_result_index - 1 < 0 { + selected_result_index = results.count-1; + if selected_result_index - (WORD_COMPLETION_MAX_RESULTS-1) > -1 { + scroll_top = selected_result_index - (WORD_COMPLETION_MAX_RESULTS-1); + } + } else { + selected_result_index -= 1; + if selected_result_index < scroll_top { + scroll_top -= 1; + } + } + + word_complete_apply(); +} + +word_complete_abort :: () { + word_complete.active = false; + word_complete.scroll_top = 0; + if !word_complete.results.count return; + for word_complete.results { free(it.word); } + array_reset(*word_complete.results); + word_complete.selected_result_index = -1; +} + +word_complete_search :: () { + editor, buffer := get_active_editor_and_buffer(); + + cursor := *editor.cursors[0]; + // right := scan_through_similar_chars_on_the_right(buffer, cursor.pos, Char_Type.word, skip_one_space = false); + right := cursor.pos; + left := scan_through_similar_chars_on_the_left(buffer, cursor.pos, Char_Type.word, skip_one_space = false); + start_subword := get_range_as_string(buffer, Offset_Range.{left, right}); + buffer_str := to_string(buffer.bytes); + + add_new_result_or_update_delta :: inline (new_result: string, cursor_delta_of_result: s64) { + for * word_complete.results { + // if we use subwords then probably we want to score things by the length too. + if it.word == new_result { + // we've found a closer one + if cursor_delta_of_result < it.cursor_delta then it.cursor_delta = xx cursor_delta_of_result; + return; + } + } + + result := Word_Result.{word = new_result, cursor_delta = xx cursor_delta_of_result}; + array_add(*word_complete.results, result); + } + + match_strictly :: inline (a: string, b: string) -> bool { + for 0..min(a.count, b.count)-1 { + if is_upper(a[it]) != is_upper(b[it]) then return false; + } + return true; + } + + // @Robustness: Searching left to right and right to left based on the first cursor position because + // I don't want to search the whole buffer for a few words. So, I used this stupid optimization, and I stuck with it. + + pos := cast(s64)(left - 1); + while pos != -1 { + if pos == 0 then pos = 1; // if in find_index_from_right_nocase start_index got 0 then it's going to start the searching from the end of the buffer + pos = find_index_from_right_nocase(buffer_str, start_subword, pos); + if pos == -1 break; + + defer pos -= 1; + if pos-1 >= 0 && is_word_char(buffer_str[pos-1]) then continue; + + for pos..buffer_str.count-1 { + c := buffer_str[it]; + if !is_word_char(c) { + is_subword := c == #char "_"; + s := advance(buffer_str, pos); + s.count = it - pos; + cursor_delta := cursor.pos - pos; + if !match_strictly(start_subword, s) then cursor_delta += 100000; // case-sensitive penalty + add_new_result_or_update_delta(s, cursor_delta); + + if !is_subword then break; + } + } + } + + pos = cast(s64)(right + 1); + while pos != buffer_str.count-1 { + pos = find_index_from_left_nocase(buffer_str, start_subword, pos); + if pos == -1 break; + + defer pos += start_subword.count; + if is_word_char(buffer_str[pos-1]) then continue; + + for pos..buffer_str.count-1 { + c := buffer_str[it]; + if !is_word_char(c) { + is_subword := c == #char "_"; + + s := advance(buffer_str, pos); + if s == start_subword continue; + s.count = it - pos; + // Now, we're going left to right, so the distance between the word and the cursor will + // always be closer than in right-to-left searching; thus, we need to apply some corrections to it. + cursor_delta := it - cursor.pos; + if !match_strictly(start_subword, s) then cursor_delta += 100000; // case-sensitive penalty + add_new_result_or_update_delta(s, cursor_delta); + + if !is_subword then break; + } + } + + } + + if !word_complete.results.count then return; + + bubble_sort(word_complete.results, (a, b) => cast(s64) (a.cursor_delta - b.cursor_delta)); + + // word_complete.results.count = min(word_complete.results.count, WORD_COMPLETION_MAX_RESULTS); + + add_new_result_or_update_delta(start_subword, cursor_delta_of_result = 0); + + for * word_complete.results { it.word = copy_string(it.word); } + + return; +} + +word_complete_apply :: () { + if !word_complete.results || !open_editors[editors.active].cursors.count return; + editor, buffer := get_active_editor_and_buffer(); + + result := word_complete.results[word_complete.selected_result_index]; + word := result.word; + + for *cursor: editor.cursors { + left := scan_through_similar_chars_on_the_left(buffer, cursor.pos, Char_Type.word, skip_one_space = false); + cursor.sel = cursor.pos; + cursor.pos = left; + select_word(buffer, cursor); + } + + offset_delta: s32 = 0; + buf_len := cast(s32) buffer.bytes.count; + for *cursor: editor.cursors { + new_len := cast(s32) buffer.bytes.count; + if new_len != buf_len { + offset_delta += new_len - buf_len; + cursor.pos += offset_delta; + cursor.sel += offset_delta; + buf_len = new_len; + } + + range := get_selection(cursor); + add_paste_animation(editor, Offset_Range.{range.start, xx (range.start+word.count)}); + replace_range(buffer, range, word); + cursor.pos = xx (range.start + word.count); + cursor.sel = cursor.pos; + } +} + #scope_export +WORD_COMPLETION_MAX_RESULTS :: 15; // @Decide: Config file or a new, scrollable popup + +Word_Completion :: struct { + active := false; + should_abort := false; + selected_result_index := -1; + // search_for_subwords := true; + results: [..] Word_Result; + scroll_top := 0; +} + +Word_Result :: struct { + word: string; + cursor_delta: s32; +} + +word_complete: Word_Completion; + Editor :: struct { buffer_id: s64; diff --git a/src/keymap.jai b/src/keymap.jai index f46206c52..95cf9898b 100644 --- a/src/keymap.jai +++ b/src/keymap.jai @@ -385,6 +385,9 @@ ACTIONS_EDITORS :: #run arrays_concat(ACTIONS_COMMON, string.[ "move_to_next_buffer", "toggle_line_wrap", "toggle_line_numbers", + "word_completion_next", + "word_completion_previous", + "word_completion_subword" ]); ACTIONS_OPEN_FILE_DIALOG :: #run arrays_concat(ACTIONS_COMMON, string.[ diff --git a/src/utils.jai b/src/utils.jai index f1dbdb172..2950df9ac 100644 --- a/src/utils.jai +++ b/src/utils.jai @@ -229,6 +229,23 @@ find_index_from_left_nocase :: (s: string, substring: string, start_index := 0) return -1; } + +find_index_from_right_nocase :: (s: string, substring: string, start_index := 0) -> s64 { + if !substring return -1; + x := s; + if start_index { + if start_index > s.count return -1; // assert? + x.count = start_index; + } + + for < i: x.count-substring.count..0 { + t := slice(x, i, substring.count); + if equal_nocase(t, substring) return i; + } + + return -1; +} + match_whole_word :: (s: string, offset: int, count: int) -> bool { before := < bool { return true; } +is_upper :: inline (byte: u8) -> bool { + if byte >= #char "A" && byte <= #char "Z" return true; + return false; +} + count_whitespace :: (bytes: [] u8, start_offset: s64, max_offset: s64, spaces := " \t") -> count: s32 { subarray := array_view(bytes, start_offset, max_offset - start_offset); for subarray { From 77427c4c6d42e1deac33f9a4fed1c2bc9aba8372 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Polg=C3=A1r?= Date: Fri, 22 Sep 2023 20:23:24 +0200 Subject: [PATCH 02/17] Wao --- modules/EGL/module.jai | 302 ----------------------------------------- 1 file changed, 302 deletions(-) delete mode 100644 modules/EGL/module.jai diff --git a/modules/EGL/module.jai b/modules/EGL/module.jai deleted file mode 100644 index b9ab49cdd..000000000 --- a/modules/EGL/module.jai +++ /dev/null @@ -1,302 +0,0 @@ -EGLDisplay :: *_EGLDisplay; -EGLConfig :: *_EGLConfig; -EGLSurface :: *_EGLSurface; -EGLContext :: *_EGLContext; - -EGLClientBuffer :: *_EGLClientBuffer; - -EGLSync :: *_EGLSync; -EGLImage :: *_EGLImage; - -EGLNativePixmapType :: *void; -EGLNativeDisplayType :: *void; -EGLNativeWindowType :: *void; - -/* EGL 1.0.1 */ -EGL_ALPHA_SIZE : s32 : 0x3021; -EGL_BAD_ACCESS : s32 : 0x3002; -EGL_BAD_ALLOC : s32 : 0x3003; -EGL_BAD_ATTRIBUTE : s32 : 0x3004; -EGL_BAD_CONFIG : s32 : 0x3005; -EGL_BAD_CONTEXT : s32 : 0x3006; -EGL_BAD_CURRENT_SURFACE : s32 : 0x3007; -EGL_BAD_DISPLAY : s32 : 0x3008; -EGL_BAD_MATCH : s32 : 0x3009; -EGL_BAD_NATIVE_PIXMAP : s32 : 0x300A; -EGL_BAD_NATIVE_WINDOW : s32 : 0x300B; -EGL_BAD_PARAMETER : s32 : 0x300C; -EGL_BAD_SURFACE : s32 : 0x300D; -EGL_BLUE_SIZE : s32 : 0x3022; -EGL_BUFFER_SIZE : s32 : 0x3020; -EGL_CONFIG_CAVEAT : s32 : 0x3027; -EGL_CONFIG_ID : s32 : 0x3028; -EGL_CORE_NATIVE_ENGINE : s32 : 0x305B; -EGL_DEPTH_SIZE : s32 : 0x3025; -EGL_DONT_CARE : s32 : -1; -EGL_DRAW : s32 : 0x3059; -EGL_EXTENSIONS : s32 : 0x3055; -EGL_FALSE : s32 : 0; -EGL_GREEN_SIZE : s32 : 0x3023; -EGL_HEIGHT : s32 : 0x3056; -EGL_LARGEST_PBUFFER : s32 : 0x3058; -EGL_LEVEL : s32 : 0x3029; -EGL_MAX_PBUFFER_HEIGHT : s32 : 0x302A; -EGL_MAX_PBUFFER_PIXELS : s32 : 0x302B; -EGL_MAX_PBUFFER_WIDTH : s32 : 0x302C; -EGL_NATIVE_RENDERABLE : s32 : 0x302D; -EGL_NATIVE_VISUAL_ID : s32 : 0x302E; -EGL_NATIVE_VISUAL_TYPE : s32 : 0x302F; -EGL_NONE : s32 : 0x3038; -EGL_NON_CONFORMANT_CONFIG : s32 : 0x3051; -EGL_NOT_INITIALIZED : s32 : 0x3001; -EGL_NO_CONTEXT :: cast(EGLContext) null; -EGL_NO_DISPLAY :: cast(EGLDisplay) null; -EGL_NO_SURFACE :: cast(EGLSurface) null; -EGL_PBUFFER_BIT : s32 : 0x0001; -EGL_PIXMAP_BIT : s32 : 0x0002; -EGL_READ : s32 : 0x305A; -EGL_RED_SIZE : s32 : 0x3024; -EGL_SAMPLES : s32 : 0x3031; -EGL_SAMPLE_BUFFERS : s32 : 0x3032; -EGL_SLOW_CONFIG : s32 : 0x3050; -EGL_STENCIL_SIZE : s32 : 0x3026; -EGL_SUCCESS : s32 : 0x3000; -EGL_SURFACE_TYPE : s32 : 0x3033; -EGL_TRANSPARENT_BLUE_VALUE : s32 : 0x3035; -EGL_TRANSPARENT_GREEN_VALUE : s32 : 0x3036; -EGL_TRANSPARENT_RED_VALUE : s32 : 0x3037; -EGL_TRANSPARENT_RGB : s32 : 0x3052; -EGL_TRANSPARENT_TYPE : s32 : 0x3034; -EGL_TRUE : s32 : 1; -EGL_VENDOR : s32 : 0x3053; -EGL_VERSION : s32 : 0x3054; -EGL_WIDTH : s32 : 0x3057; -EGL_WINDOW_BIT : s32 : 0x0004; - -eglChooseConfig :: (dpy: EGLDisplay, attrib_list: *s32, configs: *EGLConfig, config_size: s32, num_config: *s32) -> s32 #foreign libEGL; -eglCopyBuffers :: (dpy: EGLDisplay, surface: EGLSurface, target: EGLNativePixmapType) -> s32 #foreign libEGL; -eglCreateContext :: (dpy: EGLDisplay, config: EGLConfig, share_context: EGLContext, attrib_list: *s32) -> EGLContext #foreign libEGL; -eglCreatePbufferSurface :: (dpy: EGLDisplay, config: EGLConfig, attrib_list: *s32) -> EGLSurface #foreign libEGL; -eglCreatePixmapSurface :: (dpy: EGLDisplay, config: EGLConfig, pixmap: EGLNativePixmapType, attrib_list: *s32) -> EGLSurface #foreign libEGL; -eglCreateWindowSurface :: (dpy: EGLDisplay, config: EGLConfig, win: EGLNativeWindowType, attrib_list: *s32) -> EGLSurface #foreign libEGL; -eglDestroyContext :: (dpy: EGLDisplay, ctx: EGLContext) -> s32 #foreign libEGL; -eglDestroySurface :: (dpy: EGLDisplay, surface: EGLSurface) -> s32 #foreign libEGL; -eglGetConfigAttrib :: (dpy: EGLDisplay, config: EGLConfig, attribute: s32, value: *s32) -> s32 #foreign libEGL; -eglGetConfigs :: (dpy: EGLDisplay, configs: *EGLConfig, config_size: s32, num_config: *s32) -> s32 #foreign libEGL; -eglGetCurrentDisplay :: () -> EGLDisplay #foreign libEGL; -eglGetCurrentSurface :: (readdraw: s32) -> EGLSurface #foreign libEGL; -eglGetDisplay :: (display_id: EGLNativeDisplayType) -> EGLDisplay #foreign libEGL; -eglGetError :: () -> s32 #foreign libEGL; -eglGetProcAddress :: (procname: *u8) -> *void #foreign libEGL; -eglInitialize :: (dpy: EGLDisplay, major: *s32, minor: *s32) -> s32 #foreign libEGL; -eglMakeCurrent :: (dpy: EGLDisplay, draw: EGLSurface, read: EGLSurface, ctx: EGLContext) -> s32 #foreign libEGL; -eglQueryContext :: (dpy: EGLDisplay, ctx: EGLContext, attribute: s32, value: *s32) -> s32 #foreign libEGL; -eglQueryString :: (dpy: EGLDisplay, name: s32) -> *u8 #foreign libEGL; -eglQuerySurface :: (dpy: EGLDisplay, surface: EGLSurface, attribute: s32, value: *s32) -> s32 #foreign libEGL; -eglSwapBuffers :: (dpy: EGLDisplay, surface: EGLSurface) -> s32 #foreign libEGL; -eglTerminate :: (dpy: EGLDisplay) -> s32 #foreign libEGL; -eglWaitGL :: () -> s32 #foreign libEGL; -eglWaitNative :: (engine: s32) -> s32 #foreign libEGL; - -/* EGL 1.1 */ -EGL_BACK_BUFFER : s32 : 0x3084; -EGL_BIND_TO_TEXTURE_RGB : s32 : 0x3039; -EGL_BIND_TO_TEXTURE_RGBA : s32 : 0x303A; -EGL_CONTEXT_LOST : s32 : 0x300E; -EGL_MIN_SWAP_INTERVAL : s32 : 0x303B; -EGL_MAX_SWAP_INTERVAL : s32 : 0x303C; -EGL_MIPMAP_TEXTURE : s32 : 0x3082; -EGL_MIPMAP_LEVEL : s32 : 0x3083; -EGL_NO_TEXTURE : s32 : 0x305C; -EGL_TEXTURE_2D : s32 : 0x305F; -EGL_TEXTURE_FORMAT : s32 : 0x3080; -EGL_TEXTURE_RGB : s32 : 0x305D; -EGL_TEXTURE_RGBA : s32 : 0x305E; -EGL_TEXTURE_TARGET : s32 : 0x3081; - -eglBindTexImage :: (dpy: EGLDisplay, surface: EGLSurface, buffer: s32) -> s32 #foreign libEGL; -eglReleaseTexImage :: (dpy: EGLDisplay, surface: EGLSurface, buffer: s32) -> s32 #foreign libEGL; -eglSurfaceAttrib :: (dpy: EGLDisplay, surface: EGLSurface, attribute: s32, value: s32) -> s32 #foreign libEGL; -eglSwapInterval :: (dpy: EGLDisplay, interval: s32) -> s32 #foreign libEGL; - -/* EGL 1.2 */ -EGL_ALPHA_FORMAT : s32 : 0x3088; -EGL_ALPHA_FORMAT_NONPRE : s32 : 0x308B; -EGL_ALPHA_FORMAT_PRE : s32 : 0x308C; -EGL_ALPHA_MASK_SIZE : s32 : 0x303E; -EGL_BUFFER_PRESERVED : s32 : 0x3094; -EGL_BUFFER_DESTROYED : s32 : 0x3095; -EGL_CLIENT_APIS : s32 : 0x308D; -EGL_COLORSPACE : s32 : 0x3087; -EGL_COLORSPACE_sRGB : s32 : 0x3089; -EGL_COLORSPACE_LINEAR : s32 : 0x308A; -EGL_COLOR_BUFFER_TYPE : s32 : 0x303F; -EGL_CONTEXT_CLIENT_TYPE : s32 : 0x3097; -EGL_DISPLAY_SCALING : s32 : 10000; -EGL_HORIZONTAL_RESOLUTION : s32 : 0x3090; -EGL_LUMINANCE_BUFFER : s32 : 0x308F; -EGL_LUMINANCE_SIZE : s32 : 0x303D; -EGL_OPENGL_ES_BIT : s32 : 0x0001; -EGL_OPENVG_BIT : s32 : 0x0002; -EGL_OPENGL_ES_API : s32 : 0x30A0; -EGL_OPENVG_API : s32 : 0x30A1; -EGL_OPENVG_IMAGE : s32 : 0x3096; -EGL_PIXEL_ASPECT_RATIO : s32 : 0x3092; -EGL_RENDERABLE_TYPE : s32 : 0x3040; -EGL_RENDER_BUFFER : s32 : 0x3086; -EGL_RGB_BUFFER : s32 : 0x308E; -EGL_SINGLE_BUFFER : s32 : 0x3085; -EGL_SWAP_BEHAVIOR : s32 : 0x3093; -EGL_UNKNOWN : s32 : -1; -EGL_VERTICAL_RESOLUTION : s32 : 0x3091; - -eglBindAPI :: (api: s32) -> s32 #foreign libEGL; -eglQueryAPI :: () -> u32 #foreign libEGL; -eglCreatePbufferFromClientBuffer :: (dpy: EGLDisplay, buftype: u32, buffer: EGLClientBuffer, config: EGLConfig, attrib_list: *s32) -> EGLSurface #foreign libEGL; -eglReleaseThread :: () -> s32 #foreign libEGL; -eglWaitClient :: () -> s32 #foreign libEGL; - -/* EGL 1.3 */ -EGL_CONFORMANT : s32 : 0x3042; -EGL_CONTEXT_CLIENT_VERSION : s32 : 0x3098; -EGL_MATCH_NATIVE_PIXMAP : s32 : 0x3041; -EGL_OPENGL_ES2_BIT : s32 : 0x0004; -EGL_VG_ALPHA_FORMAT : s32 : 0x3088; -EGL_VG_ALPHA_FORMAT_NONPRE : s32 : 0x308B; -EGL_VG_ALPHA_FORMAT_PRE : s32 : 0x308C; -EGL_VG_ALPHA_FORMAT_PRE_BIT : s32 : 0x0040; -EGL_VG_COLORSPACE : s32 : 0x3087; -EGL_VG_COLORSPACE_sRGB : s32 : 0x3089; -EGL_VG_COLORSPACE_LINEAR : s32 : 0x308A; -EGL_VG_COLORSPACE_LINEAR_BIT : s32 : 0x0020; - -/* EGL 1.4 */ -EGL_DEFAULT_DISPLAY :: cast(EGLNativeDisplayType) null; -EGL_MULTISAMPLE_RESOLVE_BOX_BIT : s32 : 0x0200; -EGL_MULTISAMPLE_RESOLVE : s32 : 0x3099; -EGL_MULTISAMPLE_RESOLVE_DEFAULT : s32 : 0x309A; -EGL_MULTISAMPLE_RESOLVE_BOX : s32 : 0x309B; -EGL_OPENGL_API : s32 : 0x30A2; -EGL_OPENGL_BIT : s32 : 0x0008; -EGL_SWAP_BEHAVIOR_PRESERVED_BIT : s32 : 0x0400; - -/* EGL 1.5 */ -EGL_CONTEXT_MAJOR_VERSION : s32 : 0x3098; -EGL_CONTEXT_MINOR_VERSION : s32 : 0x30FB; -EGL_CONTEXT_OPENGL_PROFILE_MASK : s32 : 0x30FD; -EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY : s32 : 0x31BD; -EGL_NO_RESET_NOTIFICATION : s32 : 0x31BE; -EGL_LOSE_CONTEXT_ON_RESET : s32 : 0x31BF; -EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT : s32 : 0x00000001; -EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT : s32 : 0x00000002; -EGL_CONTEXT_OPENGL_DEBUG : s32 : 0x31B0; -EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE : s32 : 0x31B1; -EGL_CONTEXT_OPENGL_ROBUST_ACCESS : s32 : 0x31B2; -EGL_OPENGL_ES3_BIT : s32 : 0x00000040; -EGL_CL_EVENT_HANDLE : s32 : 0x309C; -EGL_SYNC_CL_EVENT : s32 : 0x30FE; -EGL_SYNC_CL_EVENT_COMPLETE : s32 : 0x30FF; -EGL_SYNC_PRIOR_COMMANDS_COMPLETE : s32 : 0x30F0; -EGL_SYNC_TYPE : s32 : 0x30F7; -EGL_SYNC_STATUS : s32 : 0x30F1; -EGL_SYNC_CONDITION : s32 : 0x30F8; -EGL_SIGNALED : s32 : 0x30F2; -EGL_UNSIGNALED : s32 : 0x30F3; -EGL_SYNC_FLUSH_COMMANDS_BIT : s32 : 0x0001; -EGL_FOREVER :: cast(u64) 0xFFFFFFFFFFFFFFFF; -EGL_TIMEOUT_EXPIRED : s32 : 0x30F5; -EGL_CONDITION_SATISFIED : s32 : 0x30F6; -EGL_NO_SYNC :: cast(EGLSync) null; -EGL_SYNC_FENCE : s32 : 0x30F9; -EGL_GL_COLORSPACE : s32 : 0x309D; -EGL_GL_COLORSPACE_SRGB : s32 : 0x3089; -EGL_GL_COLORSPACE_LINEAR : s32 : 0x308A; -EGL_GL_RENDERBUFFER : s32 : 0x30B9; -EGL_GL_TEXTURE_2D : s32 : 0x30B1; -EGL_GL_TEXTURE_LEVEL : s32 : 0x30BC; -EGL_GL_TEXTURE_3D : s32 : 0x30B2; -EGL_GL_TEXTURE_ZOFFSET : s32 : 0x30BD; -EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X : s32 : 0x30B3; -EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X : s32 : 0x30B4; -EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y : s32 : 0x30B5; -EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y : s32 : 0x30B6; -EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z : s32 : 0x30B7; -EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z : s32 : 0x30B8; -EGL_IMAGE_PRESERVED : s32 : 0x30D2; -EGL_NO_IMAGE :: cast(EGLImage) null; - -eglCreateSync :: (dpy: EGLDisplay, type: u32, attrib_list: *s64) -> EGLSync #foreign libEGL; -eglDestroySync :: (dpy: EGLDisplay, sync: EGLSync) -> s32 #foreign libEGL; -eglClientWaitSync :: (dpy: EGLDisplay, sync: EGLSync, flags: s32, timeout: u64) -> s32 #foreign libEGL; -eglGetSyncAttrib :: (dpy: EGLDisplay, sync: EGLSync, attribute: s32, value: s64) -> s32 #foreign libEGL; -eglCreateImage :: (dpy: EGLDisplay, ctx: EGLContext, target: u32, buffer: EGLClientBuffer, attrib_list: *s64) -> EGLImage #foreign libEGL; -eglDestroyImage :: (dpy: EGLDisplay, image: EGLImage) -> s32 #foreign libEGL; -eglGetPlatformDisplay :: (platform: u32, native_display: *void, attrib_list: *s64) -> EGLDisplay #foreign libEGL; -eglCreatePlatformWindowSurface :: (dpy: EGLDisplay, config: EGLConfig, native_window: *void, attrib_list: *s64) -> EGLSurface #foreign libEGL; -eglCreatePlatformPixmapSurface :: (dpy: EGLDisplay, config: EGLConfig, native_pixmap: *void, attrib_list: *s64) -> EGLSurface #foreign libEGL; -eglWaitSync :: (dpy: EGLDisplay, sync: EGLSync, flags: s32) -> s32 #foreign libEGL; - -egl_create_context :: (native_display: EGLNativeDisplayType, major_version := 0, minor_version := 0, - compatibility := false, debug := false) -> EGLDisplay, EGLContext, EGLConfig -{ - n: s32; - major: s32; - minor: s32; - - egl_dpy := eglGetDisplay(native_display); - eglInitialize(egl_dpy, *major, *minor); - eglBindAPI(EGL_OPENGL_API); - - config_attribs : []s32 = .[ - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_RED_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_BLUE_SIZE, 8, - // EGL_ALPHA_SIZE, 8, // this makes the entire window translucent - EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, - EGL_NONE - ]; - egl_cnf: EGLConfig; - eglChooseConfig(egl_dpy, config_attribs.data, *egl_cnf, 1, *n); - - context_attribs: [9]s32; - attr_count := 0; - - if major_version > 0 { - context_attribs[attr_count + 0] = EGL_CONTEXT_MAJOR_VERSION; - context_attribs[attr_count + 1] = xx major_version; - context_attribs[attr_count + 2] = EGL_CONTEXT_MINOR_VERSION; - context_attribs[attr_count + 3] = xx minor_version; - attr_count += 4; - } - - context_attribs[attr_count + 0] = EGL_CONTEXT_OPENGL_PROFILE_MASK; - if compatibility context_attribs[attr_count + 1] = EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT; - else context_attribs[attr_count + 1] = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT; - attr_count += 2; - - if debug { - context_attribs[attr_count + 0] = EGL_CONTEXT_OPENGL_DEBUG; - context_attribs[attr_count + 1] = EGL_TRUE; - attr_count += 2; - } - - context_attribs[attr_count] = EGL_NONE; - - egl_ctx := eglCreateContext(egl_dpy, egl_cnf, EGL_NO_CONTEXT, context_attribs.data); - - return egl_dpy, egl_ctx, egl_cnf; -} - -#scope_file -_EGLDisplay :: struct {} -_EGLConfig :: struct {} -_EGLSurface :: struct {} -_EGLContext :: struct {} - -_EGLClientBuffer :: struct {} - -_EGLSync :: struct {} -_EGLImage :: struct {} - -libEGL :: #system_library "libEGL"; From ac107f0bf597fac7a23482f812842813b906636a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Polg=C3=A1r?= Date: Thu, 28 Sep 2023 21:58:58 +0200 Subject: [PATCH 03/17] Word Completion - subwords, bugfixes --- src/editors.jai | 78 +++++++++++++++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 32 deletions(-) diff --git a/src/editors.jai b/src/editors.jai index 3c67feb24..e0ea8450f 100644 --- a/src/editors.jai +++ b/src/editors.jai @@ -3126,13 +3126,13 @@ word_completion :: (forwards := true, search_for_subwords := false) { word_complete.should_abort = false; // @Todo: Disabled temporary - // context.underscore_is_part_of_word = !word_complete.search_for_subwords; - // defer context.underscore_is_part_of_word = true; + context.underscore_is_part_of_word = !word_complete.search_for_subwords; + defer context.underscore_is_part_of_word = true; - // if !word_complete.active { - // word_complete.search_for_subwords = search_for_subwords; - // context.underscore_is_part_of_word = !search_for_subwords; - // } + if !word_complete.active { + word_complete.search_for_subwords = search_for_subwords; + context.underscore_is_part_of_word = !search_for_subwords; + } if !word_complete.active { word_complete.active = true; @@ -3182,29 +3182,35 @@ word_completion_previous :: () { } word_complete_abort :: () { - word_complete.active = false; - word_complete.scroll_top = 0; - if !word_complete.results.count return; - for word_complete.results { free(it.word); } - array_reset(*word_complete.results); - word_complete.selected_result_index = -1; + using word_complete; + array_reset(*cursor_backups); + active = false; + scroll_top = 0; + if !results.count return; + for results { free(it.word); } + array_reset(*results); + selected_result_index = -1; } word_complete_search :: () { editor, buffer := get_active_editor_and_buffer(); + for *cursor: editor.cursors { + array_add(*word_complete.cursor_backups, cursor.pos); + } + cursor := *editor.cursors[0]; - // right := scan_through_similar_chars_on_the_right(buffer, cursor.pos, Char_Type.word, skip_one_space = false); right := cursor.pos; left := scan_through_similar_chars_on_the_left(buffer, cursor.pos, Char_Type.word, skip_one_space = false); + word_complete.cursor_backups[0] = left; start_subword := get_range_as_string(buffer, Offset_Range.{left, right}); buffer_str := to_string(buffer.bytes); - + add_new_result_or_update_delta :: inline (new_result: string, cursor_delta_of_result: s64) { for * word_complete.results { - // if we use subwords then probably we want to score things by the length too. + // @Todo: if we use subwords then probably we want to score things by the length too. if it.word == new_result { - // we've found a closer one + // found a closer one if cursor_delta_of_result < it.cursor_delta then it.cursor_delta = xx cursor_delta_of_result; return; } @@ -3290,21 +3296,25 @@ word_complete_search :: () { } word_complete_apply :: () { - if !word_complete.results || !open_editors[editors.active].cursors.count return; + using word_complete; + + if !results || !open_editors[editors.active].cursors.count return; editor, buffer := get_active_editor_and_buffer(); - result := word_complete.results[word_complete.selected_result_index]; + result := results[selected_result_index]; word := result.word; - - for *cursor: editor.cursors { - left := scan_through_similar_chars_on_the_left(buffer, cursor.pos, Char_Type.word, skip_one_space = false); - cursor.sel = cursor.pos; - cursor.pos = left; - select_word(buffer, cursor); - } + context.underscore_is_part_of_word = true; offset_delta: s32 = 0; buf_len := cast(s32) buffer.bytes.count; + + for *cursor: editor.cursors { + if it_index >= cursor_backups.count then cursor_backups[it_index] = cursor.pos; + cursor.sel = cursor_backups[it_index]; + select_word(buffer, cursor); + s := get_selected_string(cursor, buffer); + } + for *cursor: editor.cursors { new_len := cast(s32) buffer.bytes.count; if new_len != buf_len { @@ -3312,25 +3322,29 @@ word_complete_apply :: () { cursor.pos += offset_delta; cursor.sel += offset_delta; buf_len = new_len; + + cursor_backups[it_index] = min(cursor.pos, cursor.sel); } - + range := get_selection(cursor); - add_paste_animation(editor, Offset_Range.{range.start, xx (range.start+word.count)}); replace_range(buffer, range, word); - cursor.pos = xx (range.start + word.count); - cursor.sel = cursor.pos; - } + add_paste_animation(editor, Offset_Range.{range.start, cast(s32)(range.start+word.count)}); + + cursor.pos = cast(s32)(range.start+word.count); + cursor.sel = cast(s32)(range.start+word.count); + } } #scope_export -WORD_COMPLETION_MAX_RESULTS :: 15; // @Decide: Config file or a new, scrollable popup +WORD_COMPLETION_MAX_RESULTS :: 15; Word_Completion :: struct { active := false; should_abort := false; selected_result_index := -1; - // search_for_subwords := true; + search_for_subwords := false; + cursor_backups: [..] s32; results: [..] Word_Result; scroll_top := 0; } From ae2e9e486b52832336db065de2509955ef0c38c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Polg=C3=A1r?= Date: Fri, 29 Sep 2023 16:01:14 +0200 Subject: [PATCH 04/17] Word Completion - subwords, cleanups, results scrolling fix --- src/draw.jai | 8 +++-- src/editors.jai | 87 ++++++++++++++++++++++++++----------------------- 2 files changed, 52 insertions(+), 43 deletions(-) diff --git a/src/draw.jai b/src/draw.jai index 1ffafab08..8c237e187 100644 --- a/src/draw.jai +++ b/src/draw.jai @@ -1048,7 +1048,7 @@ draw_editor :: (editor_id: s64, main_area: Rect, footer_height: float, ui_id: Ui // Draw word completion if editor_is_active && word_complete.results.count { - mm := min(word_complete.results.count, WORD_COMPLETION_MAX_RESULTS); + mm := min(word_complete.results.count, WORD_COMPLETION_MAX_VISIBLE_ITEM_AT_ONCE); padding := floor(10 * dpi_scale); item_delta_scaler := (line_height + 5) * dpi_scale; @@ -1062,8 +1062,10 @@ draw_editor :: (editor_id: s64, main_area: Rect, footer_height: float, ui_id: Ui rect_top := cursor_screen_pos.y - rect_h; rect_left := cursor_screen_pos.x + padding; - - if rect_top < 0 then rect_top = cursor_screen_pos.y + padding; + + if rect_top < 0 { + rect_top = cursor_screen_pos.y + line_height; + } if rect_left + rect_w + padding > main_area.w + main_area.x { rect_left = (main_area.w + main_area.x) - (rect_w + padding); } diff --git a/src/editors.jai b/src/editors.jai index e0ea8450f..82c6fd7b1 100644 --- a/src/editors.jai +++ b/src/editors.jai @@ -256,7 +256,7 @@ active_editor_handle_event :: (event: Input.Event, action: Action_Editors) -> ha case .word_completion_next; word_completion(); case .word_completion_previous; word_completion(forwards = false); - case .word_completion_subword; word_completion(search_for_subwords = true); + case .word_completion_subword; word_completion(subwords = true); case; return false; } @@ -3121,25 +3121,20 @@ free_editor :: (using editor: *Editor) { array_reset(*wrapped_line_starts); } -// @CleanUp: -word_completion :: (forwards := true, search_for_subwords := false) { - word_complete.should_abort = false; - - // @Todo: Disabled temporary - context.underscore_is_part_of_word = !word_complete.search_for_subwords; - defer context.underscore_is_part_of_word = true; - - if !word_complete.active { - word_complete.search_for_subwords = search_for_subwords; - context.underscore_is_part_of_word = !search_for_subwords; - } +word_completion :: (forwards := true, subwords := false) { + using word_complete; + should_abort = false; - if !word_complete.active { - word_complete.active = true; + if !active { + active = true; + search_for_subwords = subwords; + + context.underscore_is_part_of_word = !subwords; word_complete_search(); + context.underscore_is_part_of_word = true; - if word_complete.results.count == 0 { - word_complete.active = false; + if results.count == 0 { + active = false; return; } } @@ -3154,10 +3149,12 @@ word_completion_next :: () { selected_result_index = (selected_result_index + 1) % results.count; start := scroll_top; - end := start + WORD_COMPLETION_MAX_RESULTS; + end := start + WORD_COMPLETION_MAX_VISIBLE_ITEM_AT_ONCE; if selected_result_index+1 > end { scroll_top += 1; + } else if selected_result_index == 0 { + scroll_top = 0; } word_complete_apply(); @@ -3168,8 +3165,8 @@ word_completion_previous :: () { if selected_result_index - 1 < 0 { selected_result_index = results.count-1; - if selected_result_index - (WORD_COMPLETION_MAX_RESULTS-1) > -1 { - scroll_top = selected_result_index - (WORD_COMPLETION_MAX_RESULTS-1); + if selected_result_index - (WORD_COMPLETION_MAX_VISIBLE_ITEM_AT_ONCE-1) > -1 { + scroll_top = selected_result_index - (WORD_COMPLETION_MAX_VISIBLE_ITEM_AT_ONCE-1); } } else { selected_result_index -= 1; @@ -3193,6 +3190,10 @@ word_complete_abort :: () { } word_complete_search :: () { + // hmm... + UNDERSCORE_PENALTY :: 1000000000; + CASE_SENSITIVE_PENALTY :: 100000000; + editor, buffer := get_active_editor_and_buffer(); for *cursor: editor.cursors { @@ -3204,19 +3205,28 @@ word_complete_search :: () { left := scan_through_similar_chars_on_the_left(buffer, cursor.pos, Char_Type.word, skip_one_space = false); word_complete.cursor_backups[0] = left; start_subword := get_range_as_string(buffer, Offset_Range.{left, right}); + buffer_str := to_string(buffer.bytes); - add_new_result_or_update_delta :: inline (new_result: string, cursor_delta_of_result: s64) { + add_new_result_or_update_delta :: inline (new_result: string, delta: s64) { + if word_complete.search_for_subwords { + for 0..new_result.count-1 { + if new_result[it] == #char "_" { + delta += UNDERSCORE_PENALTY; + break; + } + } + } + for * word_complete.results { - // @Todo: if we use subwords then probably we want to score things by the length too. if it.word == new_result { // found a closer one - if cursor_delta_of_result < it.cursor_delta then it.cursor_delta = xx cursor_delta_of_result; + if delta < it.cursor_delta then it.cursor_delta = xx delta; return; } } - result := Word_Result.{word = new_result, cursor_delta = xx cursor_delta_of_result}; + result := Word_Result.{word = new_result, cursor_delta = xx delta}; array_add(*word_complete.results, result); } @@ -3233,7 +3243,7 @@ word_complete_search :: () { pos := cast(s64)(left - 1); while pos != -1 { if pos == 0 then pos = 1; // if in find_index_from_right_nocase start_index got 0 then it's going to start the searching from the end of the buffer - pos = find_index_from_right_nocase(buffer_str, start_subword, pos); + pos = find_index_from_right_nocase(buffer_str, start_subword, start_index = pos); if pos == -1 break; defer pos -= 1; @@ -3246,7 +3256,7 @@ word_complete_search :: () { s := advance(buffer_str, pos); s.count = it - pos; cursor_delta := cursor.pos - pos; - if !match_strictly(start_subword, s) then cursor_delta += 100000; // case-sensitive penalty + if !match_strictly(start_subword, s) then cursor_delta += CASE_SENSITIVE_PENALTY; add_new_result_or_update_delta(s, cursor_delta); if !is_subword then break; @@ -3273,7 +3283,7 @@ word_complete_search :: () { // Now, we're going left to right, so the distance between the word and the cursor will // always be closer than in right-to-left searching; thus, we need to apply some corrections to it. cursor_delta := it - cursor.pos; - if !match_strictly(start_subword, s) then cursor_delta += 100000; // case-sensitive penalty + if !match_strictly(start_subword, s) then cursor_delta += CASE_SENSITIVE_PENALTY; add_new_result_or_update_delta(s, cursor_delta); if !is_subword then break; @@ -3283,13 +3293,10 @@ word_complete_search :: () { } if !word_complete.results.count then return; - - bubble_sort(word_complete.results, (a, b) => cast(s64) (a.cursor_delta - b.cursor_delta)); - - // word_complete.results.count = min(word_complete.results.count, WORD_COMPLETION_MAX_RESULTS); - - add_new_result_or_update_delta(start_subword, cursor_delta_of_result = 0); - + + bubble_sort(word_complete.results, (a, b) => cast(s64) ((a.cursor_delta) - (b.cursor_delta))); + + add_new_result_or_update_delta(start_subword, delta = 0); for * word_complete.results { it.word = copy_string(it.word); } return; @@ -3304,7 +3311,6 @@ word_complete_apply :: () { result := results[selected_result_index]; word := result.word; - context.underscore_is_part_of_word = true; offset_delta: s32 = 0; buf_len := cast(s32) buffer.bytes.count; @@ -3312,7 +3318,6 @@ word_complete_apply :: () { if it_index >= cursor_backups.count then cursor_backups[it_index] = cursor.pos; cursor.sel = cursor_backups[it_index]; select_word(buffer, cursor); - s := get_selected_string(cursor, buffer); } for *cursor: editor.cursors { @@ -3328,16 +3333,18 @@ word_complete_apply :: () { range := get_selection(cursor); replace_range(buffer, range, word); - add_paste_animation(editor, Offset_Range.{range.start, cast(s32)(range.start+word.count)}); - cursor.pos = cast(s32)(range.start+word.count); - cursor.sel = cast(s32)(range.start+word.count); + end := cast(s32)(range.start+word.count); + add_paste_animation(editor, Offset_Range.{range.start, end}); + + cursor.pos = end; + cursor.sel = end; } } #scope_export -WORD_COMPLETION_MAX_RESULTS :: 15; +WORD_COMPLETION_MAX_VISIBLE_ITEM_AT_ONCE :: 15; Word_Completion :: struct { active := false; From ea94b19e5994569717ae46d9dd3fd0d6936abec2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Polg=C3=A1r?= Date: Fri, 29 Sep 2023 19:25:25 +0200 Subject: [PATCH 05/17] Word Completion - Handle drastically small heights --- src/draw.jai | 43 ++++++++++++++++++++++++++++--------------- src/editors.jai | 11 ++++++----- 2 files changed, 34 insertions(+), 20 deletions(-) diff --git a/src/draw.jai b/src/draw.jai index 8c237e187..a8d2b3298 100644 --- a/src/draw.jai +++ b/src/draw.jai @@ -1048,8 +1048,9 @@ draw_editor :: (editor_id: s64, main_area: Rect, footer_height: float, ui_id: Ui // Draw word completion if editor_is_active && word_complete.results.count { - mm := min(word_complete.results.count, WORD_COMPLETION_MAX_VISIBLE_ITEM_AT_ONCE); - + word_complete.max_visible_item_at_once = word_complete.DEFAULT_MAX_VISIBLE_ITEM; + max_wc_item: s64 = min(word_complete.results.count, word_complete.max_visible_item_at_once); + padding := floor(10 * dpi_scale); item_delta_scaler := (line_height + 5) * dpi_scale; cursor := cursors[0]; @@ -1057,27 +1058,39 @@ draw_editor :: (editor_id: s64, main_area: Rect, footer_height: float, ui_id: Ui max_char := 0; for word_complete.results { if it.word.count > max_char max_char = it.word.count; } - rect_w := (max_char * char_x_advance) + (padding * 2); - rect_h := mm * (item_delta_scaler) + padding; - - rect_top := cursor_screen_pos.y - rect_h; - rect_left := cursor_screen_pos.x + padding; - - if rect_top < 0 { - rect_top = cursor_screen_pos.y + line_height; + + rect_w, rect_h, rect_left, rect_bottom: float = 0; + calc_rect :: () #expand { + rect_w = (max_char * char_x_advance) + (padding * 2); + rect_h = max_wc_item * (item_delta_scaler) + padding; + rect_bottom = cursor_screen_pos.y - rect_h; + rect_left = cursor_screen_pos.x + padding; + + if rect_bottom < footer_rect.h { + rect_bottom = cursor_screen_pos.y + line_height; + } + if rect_left + rect_w + padding > main_area.w + main_area.x { + rect_left = (main_area.w + main_area.x) - (rect_w + padding); + } } - if rect_left + rect_w + padding > main_area.w + main_area.x { - rect_left = (main_area.w + main_area.x) - (rect_w + padding); + calc_rect(); + + rect_top := rect_bottom + rect_h; + if (rect_top > main_area.h) { + usable_h := main_area.h - footer_rect.h; + max_wc_item = cast(s64)(usable_h / item_delta_scaler / 2); + word_complete.max_visible_item_at_once = max_wc_item; + calc_rect(); } - rect := make_rect(rect_left, rect_top, rect_w, rect_h); + rect := make_rect(rect_left, rect_bottom, rect_w, rect_h); draw_rounded_rect(rect, Colors.BACKGROUND_DARK, radius = rounding_radius_small, set_shader = true); i := 0; - for word_complete.scroll_top..mm+word_complete.scroll_top-1 { + for word_complete.scroll_top..max_wc_item + word_complete.scroll_top - 1 { if it == word_complete.results.count then break; item_left := rect_left + padding; - item_top := (rect_top + rect_h) - (item_delta_scaler * (i + 1)); + item_top := (rect_bottom + rect_h) - (item_delta_scaler * (i + 1)); item_color := ifx (it % word_complete.results.count) == word_complete.selected_result_index then Colors.CODE_OPERATION else Colors.CODE_DEFAULT diff --git a/src/editors.jai b/src/editors.jai index 82c6fd7b1..12c235565 100644 --- a/src/editors.jai +++ b/src/editors.jai @@ -3149,7 +3149,7 @@ word_completion_next :: () { selected_result_index = (selected_result_index + 1) % results.count; start := scroll_top; - end := start + WORD_COMPLETION_MAX_VISIBLE_ITEM_AT_ONCE; + end := start + max_visible_item_at_once; if selected_result_index+1 > end { scroll_top += 1; @@ -3165,8 +3165,8 @@ word_completion_previous :: () { if selected_result_index - 1 < 0 { selected_result_index = results.count-1; - if selected_result_index - (WORD_COMPLETION_MAX_VISIBLE_ITEM_AT_ONCE-1) > -1 { - scroll_top = selected_result_index - (WORD_COMPLETION_MAX_VISIBLE_ITEM_AT_ONCE-1); + if selected_result_index - (max_visible_item_at_once-1) > -1 { + scroll_top = selected_result_index - (max_visible_item_at_once-1); } } else { selected_result_index -= 1; @@ -3344,9 +3344,9 @@ word_complete_apply :: () { #scope_export -WORD_COMPLETION_MAX_VISIBLE_ITEM_AT_ONCE :: 15; - Word_Completion :: struct { + DEFAULT_MAX_VISIBLE_ITEM :: 15; + active := false; should_abort := false; selected_result_index := -1; @@ -3354,6 +3354,7 @@ Word_Completion :: struct { cursor_backups: [..] s32; results: [..] Word_Result; scroll_top := 0; + max_visible_item_at_once := DEFAULT_MAX_VISIBLE_ITEM; } Word_Result :: struct { From 686447a24a401e562f44bcc9e96d4d14e06a47e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Polg=C3=A1r?= Date: Fri, 29 Sep 2023 19:32:29 +0200 Subject: [PATCH 06/17] Word Completion - Cleanups --- src/editors.jai | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/editors.jai b/src/editors.jai index 12c235565..ef0a54180 100644 --- a/src/editors.jai +++ b/src/editors.jai @@ -3180,7 +3180,6 @@ word_completion_previous :: () { word_complete_abort :: () { using word_complete; - array_reset(*cursor_backups); active = false; scroll_top = 0; if !results.count return; @@ -3196,14 +3195,9 @@ word_complete_search :: () { editor, buffer := get_active_editor_and_buffer(); - for *cursor: editor.cursors { - array_add(*word_complete.cursor_backups, cursor.pos); - } - cursor := *editor.cursors[0]; right := cursor.pos; left := scan_through_similar_chars_on_the_left(buffer, cursor.pos, Char_Type.word, skip_one_space = false); - word_complete.cursor_backups[0] = left; start_subword := get_range_as_string(buffer, Offset_Range.{left, right}); buffer_str := to_string(buffer.bytes); @@ -3315,9 +3309,8 @@ word_complete_apply :: () { buf_len := cast(s32) buffer.bytes.count; for *cursor: editor.cursors { - if it_index >= cursor_backups.count then cursor_backups[it_index] = cursor.pos; - cursor.sel = cursor_backups[it_index]; - select_word(buffer, cursor); + left := scan_through_similar_chars_on_the_left(buffer, cursor.pos, Char_Type.word, skip_one_space = false); + cursor.sel = left; } for *cursor: editor.cursors { @@ -3327,8 +3320,6 @@ word_complete_apply :: () { cursor.pos += offset_delta; cursor.sel += offset_delta; buf_len = new_len; - - cursor_backups[it_index] = min(cursor.pos, cursor.sel); } range := get_selection(cursor); @@ -3351,7 +3342,6 @@ Word_Completion :: struct { should_abort := false; selected_result_index := -1; search_for_subwords := false; - cursor_backups: [..] s32; results: [..] Word_Result; scroll_top := 0; max_visible_item_at_once := DEFAULT_MAX_VISIBLE_ITEM; From 028c842e07293587990a8f50043ad440fa7f8083 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Polg=C3=A1r?= Date: Fri, 29 Sep 2023 21:13:44 +0200 Subject: [PATCH 07/17] Word Complete - MAX_TOTAL_RESULT --- src/editors.jai | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/editors.jai b/src/editors.jai index ef0a54180..877350195 100644 --- a/src/editors.jai +++ b/src/editors.jai @@ -3189,6 +3189,8 @@ word_complete_abort :: () { } word_complete_search :: () { + // @Bug: Let's say you have a comment like "yes, we're here!" then the "re" will be recognized as a separate word. + // hmm... UNDERSCORE_PENALTY :: 1000000000; CASE_SENSITIVE_PENALTY :: 100000000; @@ -3236,6 +3238,7 @@ word_complete_search :: () { pos := cast(s64)(left - 1); while pos != -1 { + if word_complete.results.count == word_complete.MAX_TOTAL_RESULT break; if pos == 0 then pos = 1; // if in find_index_from_right_nocase start_index got 0 then it's going to start the searching from the end of the buffer pos = find_index_from_right_nocase(buffer_str, start_subword, start_index = pos); if pos == -1 break; @@ -3257,9 +3260,10 @@ word_complete_search :: () { } } } - + pos = cast(s64)(right + 1); while pos != buffer_str.count-1 { + if word_complete.results.count == word_complete.MAX_TOTAL_RESULT break; pos = find_index_from_left_nocase(buffer_str, start_subword, pos); if pos == -1 break; @@ -3287,7 +3291,7 @@ word_complete_search :: () { } if !word_complete.results.count then return; - + bubble_sort(word_complete.results, (a, b) => cast(s64) ((a.cursor_delta) - (b.cursor_delta))); add_new_result_or_update_delta(start_subword, delta = 0); @@ -3337,6 +3341,7 @@ word_complete_apply :: () { Word_Completion :: struct { DEFAULT_MAX_VISIBLE_ITEM :: 15; + MAX_TOTAL_RESULT :: 35; active := false; should_abort := false; From fec690b2db29de33b3be9f87e794984928e20fa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Polg=C3=A1r?= Date: Fri, 29 Sep 2023 23:36:06 +0200 Subject: [PATCH 08/17] Word Completion - Miau --- src/draw.jai | 1 - 1 file changed, 1 deletion(-) diff --git a/src/draw.jai b/src/draw.jai index a8d2b3298..d7ba7f51c 100644 --- a/src/draw.jai +++ b/src/draw.jai @@ -1053,7 +1053,6 @@ draw_editor :: (editor_id: s64, main_area: Rect, footer_height: float, ui_id: Ui padding := floor(10 * dpi_scale); item_delta_scaler := (line_height + 5) * dpi_scale; - cursor := cursors[0]; cursor_screen_pos := get_cursor_screen_pos(text_origin, cursor_coords[0].pos); max_char := 0; From 6cee2e6a50aa997381a96e79e28d35dca04f5007 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Polg=C3=A1r?= Date: Sat, 30 Sep 2023 13:52:49 +0200 Subject: [PATCH 09/17] Word Completion - Larger rect radius --- src/draw.jai | 3 +-- src/editors.jai | 7 ++----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/draw.jai b/src/draw.jai index d7ba7f51c..bde82b75c 100644 --- a/src/draw.jai +++ b/src/draw.jai @@ -7,7 +7,6 @@ draw_frame :: () { maybe_set_hot_or_active(.none, screen, .NORMAL); - // Check whether we need to deactivate elements before drawing if (!mouse.left.is_down || mouse.left.just_released) && (!mouse.middle.is_down || mouse.middle.just_released) then ui.active = .none; @@ -1083,7 +1082,7 @@ draw_editor :: (editor_id: s64, main_area: Rect, footer_height: float, ui_id: Ui } rect := make_rect(rect_left, rect_bottom, rect_w, rect_h); - draw_rounded_rect(rect, Colors.BACKGROUND_DARK, radius = rounding_radius_small, set_shader = true); + draw_rounded_rect(rect, Colors.BACKGROUND_DARK, radius = rounding_radius_large, set_shader = true); i := 0; for word_complete.scroll_top..max_wc_item + word_complete.scroll_top - 1 { diff --git a/src/editors.jai b/src/editors.jai index 877350195..6ec45fc68 100644 --- a/src/editors.jai +++ b/src/editors.jai @@ -3126,17 +3126,14 @@ word_completion :: (forwards := true, subwords := false) { should_abort = false; if !active { - active = true; search_for_subwords = subwords; context.underscore_is_part_of_word = !subwords; word_complete_search(); context.underscore_is_part_of_word = true; - if results.count == 0 { - active = false; - return; - } + if results.count == 0 then return; + active = true; } if forwards word_completion_next(); From 6142b1534f79d4740b08b0103a5bf93cb324402a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Polg=C3=A1r?= Date: Mon, 2 Oct 2023 16:35:21 +0200 Subject: [PATCH 10/17] Word Completion - Dude --- src/editors.jai | 41 +++++++++-------------------------------- 1 file changed, 9 insertions(+), 32 deletions(-) diff --git a/src/editors.jai b/src/editors.jai index 6ec45fc68..f84d2c424 100644 --- a/src/editors.jai +++ b/src/editors.jai @@ -3230,42 +3230,15 @@ word_complete_search :: () { return true; } - // @Robustness: Searching left to right and right to left based on the first cursor position because - // I don't want to search the whole buffer for a few words. So, I used this stupid optimization, and I stuck with it. - - pos := cast(s64)(left - 1); - while pos != -1 { - if word_complete.results.count == word_complete.MAX_TOTAL_RESULT break; - if pos == 0 then pos = 1; // if in find_index_from_right_nocase start_index got 0 then it's going to start the searching from the end of the buffer - pos = find_index_from_right_nocase(buffer_str, start_subword, start_index = pos); - if pos == -1 break; - - defer pos -= 1; - if pos-1 >= 0 && is_word_char(buffer_str[pos-1]) then continue; - - for pos..buffer_str.count-1 { - c := buffer_str[it]; - if !is_word_char(c) { - is_subword := c == #char "_"; - s := advance(buffer_str, pos); - s.count = it - pos; - cursor_delta := cursor.pos - pos; - if !match_strictly(start_subword, s) then cursor_delta += CASE_SENSITIVE_PENALTY; - add_new_result_or_update_delta(s, cursor_delta); - - if !is_subword then break; - } - } - } - - pos = cast(s64)(right + 1); + pos := 0; while pos != buffer_str.count-1 { - if word_complete.results.count == word_complete.MAX_TOTAL_RESULT break; pos = find_index_from_left_nocase(buffer_str, start_subword, pos); if pos == -1 break; defer pos += start_subword.count; - if is_word_char(buffer_str[pos-1]) then continue; + if is_word_char(buffer_str[pos-1]) || pos == left { + continue; + } for pos..buffer_str.count-1 { c := buffer_str[it]; @@ -3277,7 +3250,11 @@ word_complete_search :: () { s.count = it - pos; // Now, we're going left to right, so the distance between the word and the cursor will // always be closer than in right-to-left searching; thus, we need to apply some corrections to it. - cursor_delta := it - cursor.pos; + cursor_delta := cursor.pos - pos; + if pos > right { + cursor_delta = it - cursor.pos; + } + if !match_strictly(start_subword, s) then cursor_delta += CASE_SENSITIVE_PENALTY; add_new_result_or_update_delta(s, cursor_delta); From 951a5803e7ab6f96673407eb5d055ee1125891c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Polg=C3=A1r?= Date: Sat, 7 Oct 2023 14:31:58 +0200 Subject: [PATCH 11/17] Word Completion - Improved usability --- src/draw.jai | 24 ++++++++++++++++++++++-- src/editors.jai | 39 +++++++++++++++------------------------ 2 files changed, 37 insertions(+), 26 deletions(-) diff --git a/src/draw.jai b/src/draw.jai index bde82b75c..58a98a4c5 100644 --- a/src/draw.jai +++ b/src/draw.jai @@ -1047,6 +1047,7 @@ draw_editor :: (editor_id: s64, main_area: Rect, footer_height: float, ui_id: Ui // Draw word completion if editor_is_active && word_complete.results.count { + word_complete.max_visible_item_at_once = word_complete.DEFAULT_MAX_VISIBLE_ITEM; max_wc_item: s64 = min(word_complete.results.count, word_complete.max_visible_item_at_once); @@ -1061,11 +1062,11 @@ draw_editor :: (editor_id: s64, main_area: Rect, footer_height: float, ui_id: Ui calc_rect :: () #expand { rect_w = (max_char * char_x_advance) + (padding * 2); rect_h = max_wc_item * (item_delta_scaler) + padding; - rect_bottom = cursor_screen_pos.y - rect_h; + rect_bottom = cursor_screen_pos.y - rect_h + item_delta_scaler; rect_left = cursor_screen_pos.x + padding; if rect_bottom < footer_rect.h { - rect_bottom = cursor_screen_pos.y + line_height; + rect_bottom = footer_rect.h + line_height; } if rect_left + rect_w + padding > main_area.w + main_area.x { rect_left = (main_area.w + main_area.x) - (rect_w + padding); @@ -1075,6 +1076,7 @@ draw_editor :: (editor_id: s64, main_area: Rect, footer_height: float, ui_id: Ui rect_top := rect_bottom + rect_h; if (rect_top > main_area.h) { + // Reduce the max visible results if there is no more space to expand at the top usable_h := main_area.h - footer_rect.h; max_wc_item = cast(s64)(usable_h / item_delta_scaler / 2); word_complete.max_visible_item_at_once = max_wc_item; @@ -1098,6 +1100,24 @@ draw_editor :: (editor_id: s64, main_area: Rect, footer_height: float, ui_id: Ui i+=1; } + + { + shadow_rect := make_rect(rect_left, rect_bottom, rect_w, rect_h); + using shadow_rect; + if (word_complete.scroll_top) { + Simp.set_shader_for_color(enable_blend = true); + s := Colors.SHADOW_DARK; + t := Colors.SHADOW_TRANSPARENT; + Simp.immediate_quad(x, y+h, x + w, y+h - 45.0 * dpi_scale, c00 = s, c01 = t, c10 = s, c11 = t); + } + + if (word_complete.results.count > word_complete.scroll_top + max_wc_item) { + Simp.set_shader_for_color(enable_blend = true); + s := Colors.SHADOW_DARK; + t := Colors.SHADOW_TRANSPARENT; + Simp.immediate_quad(x, y, x + w, y + 30.0 * dpi_scale, c00 = s, c01 = t, c10 = s, c11 = t); + } + } } // Draw search bar diff --git a/src/editors.jai b/src/editors.jai index f84d2c424..380d7e4b1 100644 --- a/src/editors.jai +++ b/src/editors.jai @@ -3186,8 +3186,6 @@ word_complete_abort :: () { } word_complete_search :: () { - // @Bug: Let's say you have a comment like "yes, we're here!" then the "re" will be recognized as a separate word. - // hmm... UNDERSCORE_PENALTY :: 1000000000; CASE_SENSITIVE_PENALTY :: 100000000; @@ -3198,6 +3196,7 @@ word_complete_search :: () { right := cursor.pos; left := scan_through_similar_chars_on_the_left(buffer, cursor.pos, Char_Type.word, skip_one_space = false); start_subword := get_range_as_string(buffer, Offset_Range.{left, right}); + if start_subword.count == 0 then return; buffer_str := to_string(buffer.bytes); @@ -3216,48 +3215,40 @@ word_complete_search :: () { // found a closer one if delta < it.cursor_delta then it.cursor_delta = xx delta; return; - } + } } result := Word_Result.{word = new_result, cursor_delta = xx delta}; array_add(*word_complete.results, result); } - match_strictly :: inline (a: string, b: string) -> bool { - for 0..min(a.count, b.count)-1 { - if is_upper(a[it]) != is_upper(b[it]) then return false; - } - return true; - } - pos := 0; while pos != buffer_str.count-1 { pos = find_index_from_left_nocase(buffer_str, start_subword, pos); if pos == -1 break; defer pos += start_subword.count; - if is_word_char(buffer_str[pos-1]) || pos == left { + if pos > 0 && is_word_char(buffer_str[pos-1]) { + // Exclude results that are part of another word. For instance, if your subword is 'ine' and you have a word like 'wine' elsewhere, it will not include the result 'ine' from 'w[ine]'. continue; } for pos..buffer_str.count-1 { c := buffer_str[it]; - if !is_word_char(c) { + if !is_word_char(c) || it == buffer_str.count-1 { is_subword := c == #char "_"; - s := advance(buffer_str, pos); - if s == start_subword continue; - s.count = it - pos; - // Now, we're going left to right, so the distance between the word and the cursor will - // always be closer than in right-to-left searching; thus, we need to apply some corrections to it. - cursor_delta := cursor.pos - pos; - if pos > right { - cursor_delta = it - cursor.pos; + s := advance(buffer_str, pos); + if it != buffer_str.count-1 then s.count = it - pos; + if s != start_subword { + // Now, we're going left to right, so the distance between the word and the cursor will + // always be closer than in right-to-left searching; thus, we need to apply some corrections to it. + cursor_delta := cursor.pos - pos; + if pos >= right then cursor_delta = it - cursor.pos; + if is_upper(start_subword[0]) != is_upper(buffer_str[pos]) then cursor_delta += CASE_SENSITIVE_PENALTY; + add_new_result_or_update_delta(s, cursor_delta); } - if !match_strictly(start_subword, s) then cursor_delta += CASE_SENSITIVE_PENALTY; - add_new_result_or_update_delta(s, cursor_delta); - if !is_subword then break; } } @@ -3314,7 +3305,7 @@ word_complete_apply :: () { #scope_export Word_Completion :: struct { - DEFAULT_MAX_VISIBLE_ITEM :: 15; + DEFAULT_MAX_VISIBLE_ITEM :: 8; MAX_TOTAL_RESULT :: 35; active := false; From 662e640d4a223fdaeefa840feedceacc8b0168ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Polg=C3=A1r?= Date: Mon, 9 Oct 2023 21:02:40 +0200 Subject: [PATCH 12/17] Word Completion - Improved usability --- src/draw.jai | 26 +++++++++----------------- src/editors.jai | 2 +- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/src/draw.jai b/src/draw.jai index 58a98a4c5..977a3b71d 100644 --- a/src/draw.jai +++ b/src/draw.jai @@ -1063,7 +1063,7 @@ draw_editor :: (editor_id: s64, main_area: Rect, footer_height: float, ui_id: Ui rect_w = (max_char * char_x_advance) + (padding * 2); rect_h = max_wc_item * (item_delta_scaler) + padding; rect_bottom = cursor_screen_pos.y - rect_h + item_delta_scaler; - rect_left = cursor_screen_pos.x + padding; + rect_left = cursor_screen_pos.x + padding*2; if rect_bottom < footer_rect.h { rect_bottom = footer_rect.h + line_height; @@ -1101,22 +1101,14 @@ draw_editor :: (editor_id: s64, main_area: Rect, footer_height: float, ui_id: Ui i+=1; } - { - shadow_rect := make_rect(rect_left, rect_bottom, rect_w, rect_h); - using shadow_rect; - if (word_complete.scroll_top) { - Simp.set_shader_for_color(enable_blend = true); - s := Colors.SHADOW_DARK; - t := Colors.SHADOW_TRANSPARENT; - Simp.immediate_quad(x, y+h, x + w, y+h - 45.0 * dpi_scale, c00 = s, c01 = t, c10 = s, c11 = t); - } - - if (word_complete.results.count > word_complete.scroll_top + max_wc_item) { - Simp.set_shader_for_color(enable_blend = true); - s := Colors.SHADOW_DARK; - t := Colors.SHADOW_TRANSPARENT; - Simp.immediate_quad(x, y, x + w, y + 30.0 * dpi_scale, c00 = s, c01 = t, c10 = s, c11 = t); - } + if (word_complete.scroll_top) { + Simp.prepare_text(font_ui_small, BULLET_ICON); + Simp.draw_prepared_text(font_ui_small, xx (rect_left + (rect_w/2)), xx (rect_bottom+rect_h-line_height/2), color = Colors.UI_DEFAULT); + } + + if (word_complete.results.count > word_complete.scroll_top + max_wc_item) { + Simp.prepare_text(font_ui_small, BULLET_ICON); + Simp.draw_prepared_text(font_ui_small, xx (rect_left + (rect_w/2)), xx rect_bottom, color = Colors.UI_DEFAULT); } } diff --git a/src/editors.jai b/src/editors.jai index 380d7e4b1..0f8634215 100644 --- a/src/editors.jai +++ b/src/editors.jai @@ -3305,7 +3305,7 @@ word_complete_apply :: () { #scope_export Word_Completion :: struct { - DEFAULT_MAX_VISIBLE_ITEM :: 8; + DEFAULT_MAX_VISIBLE_ITEM :: 10; MAX_TOTAL_RESULT :: 35; active := false; From 5f8c9100b3ded74dc7614ba974cd435317d45d26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Polg=C3=A1r?= Date: Tue, 10 Oct 2023 18:04:41 +0200 Subject: [PATCH 13/17] Word Complete - Fixed result box alignment --- src/draw.jai | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/draw.jai b/src/draw.jai index 977a3b71d..aea398da3 100644 --- a/src/draw.jai +++ b/src/draw.jai @@ -1062,7 +1062,7 @@ draw_editor :: (editor_id: s64, main_area: Rect, footer_height: float, ui_id: Ui calc_rect :: () #expand { rect_w = (max_char * char_x_advance) + (padding * 2); rect_h = max_wc_item * (item_delta_scaler) + padding; - rect_bottom = cursor_screen_pos.y - rect_h + item_delta_scaler; + rect_bottom = cursor_screen_pos.y - rect_h; rect_left = cursor_screen_pos.x + padding*2; if rect_bottom < footer_rect.h { From 4bf8f2b102395f277afad904596b84b141f48c53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Polg=C3=A1r?= Date: Sun, 3 Dec 2023 18:01:31 +0100 Subject: [PATCH 14/17] Hotfix --- src/editors.jai | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/editors.jai b/src/editors.jai index fd301086c..91594700f 100644 --- a/src/editors.jai +++ b/src/editors.jai @@ -3294,23 +3294,23 @@ word_complete_search :: () { if pos == -1 break; defer pos += start_subword.count; - if pos > 0 && is_word_char(buffer_str[pos-1]) { + if pos == left || (pos > 0 && is_word_char(buffer_str[pos-1])) { // Exclude results that are part of another word. For instance, if your subword is 'ine' and you have a word like 'wine' elsewhere, it will not include the result 'ine' from 'w[ine]'. continue; } - for pos..buffer_str.count-1 { - c := buffer_str[it]; - if !is_word_char(c) || it == buffer_str.count-1 { + for i: pos..buffer_str.count-1 { + c := buffer_str[i]; + if !is_word_char(c) || i == buffer_str.count-1 { is_subword := c == #char "_"; s := advance(buffer_str, pos); - if it != buffer_str.count-1 then s.count = it - pos; + s.count = i - pos; if s != start_subword { // Now, we're going left to right, so the distance between the word and the cursor will // always be closer than in right-to-left searching; thus, we need to apply some corrections to it. cursor_delta := cursor.pos - pos; - if pos >= right then cursor_delta = it - cursor.pos; + if pos >= right then cursor_delta = i - cursor.pos; if is_upper(start_subword[0]) != is_upper(buffer_str[pos]) then cursor_delta += CASE_SENSITIVE_PENALTY; add_new_result_or_update_delta(s, cursor_delta); } From 9e7abea74ede50f4a9f1c672f6bcda185a20ae02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Polg=C3=A1r?= Date: Thu, 7 Dec 2023 12:28:04 +0100 Subject: [PATCH 15/17] to_string replace --- src/editors.jai | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/editors.jai b/src/editors.jai index 91594700f..4447335ce 100644 --- a/src/editors.jai +++ b/src/editors.jai @@ -3264,7 +3264,7 @@ word_complete_search :: () { start_subword := get_range_as_string(buffer, Offset_Range.{left, right}); if start_subword.count == 0 then return; - buffer_str := to_string(buffer.bytes); + buffer_str := cast(string)buffer.bytes; add_new_result_or_update_delta :: inline (new_result: string, delta: s64) { if word_complete.search_for_subwords { From 7efe77b1c84f9c16377ca2dbd5c20825adbe2800 Mon Sep 17 00:00:00 2001 From: polgar tamas Date: Tue, 6 Aug 2024 23:25:56 +0200 Subject: [PATCH 16/17] Fixed word completion draw --- src/draw.jai | 22 ++++++++++++---------- src/keymap.jai | 5 +++-- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/draw.jai b/src/draw.jai index d46a3f18a..0d41743bb 100644 --- a/src/draw.jai +++ b/src/draw.jai @@ -1224,8 +1224,8 @@ draw_editor :: (editor_id: s64, main_area: Rect, status_bar_height: float, ui_id rect_bottom = cursor_screen_pos.y - rect_h; rect_left = cursor_screen_pos.x + padding*2; - if rect_bottom < footer_rect.h { - rect_bottom = footer_rect.h + line_height; + if rect_bottom < line_number_panel.h { + rect_bottom = line_number_panel.h + line_height; } if rect_left + rect_w + padding > main_area.w + main_area.x { rect_left = (main_area.w + main_area.x) - (rect_w + padding); @@ -1236,38 +1236,40 @@ draw_editor :: (editor_id: s64, main_area: Rect, status_bar_height: float, ui_id rect_top := rect_bottom + rect_h; if (rect_top > main_area.h) { // Reduce the max visible results if there is no more space to expand at the top - usable_h := main_area.h - footer_rect.h; + usable_h := main_area.h - line_number_panel.h; max_wc_item = cast(s64)(usable_h / item_delta_scaler / 2); word_complete.max_visible_item_at_once = max_wc_item; calc_rect(); } rect := make_rect(rect_left, rect_bottom, rect_w, rect_h); - draw_rounded_rect(rect, Colors.BACKGROUND_DARK, radius = rounding_radius_large, set_shader = true); + background_dark := Color.BACKGROUND_1; + draw_rounded_rect(rect, background_dark, radius = rounding_radius_large, set_shader = true); i := 0; for word_complete.scroll_top..max_wc_item + word_complete.scroll_top - 1 { if it == word_complete.results.count then break; item_left := rect_left + padding; item_top := (rect_bottom + rect_h) - (item_delta_scaler * (i + 1)); - item_color := ifx (it % word_complete.results.count) == word_complete.selected_result_index - then Colors.CODE_OPERATION - else Colors.CODE_DEFAULT + item_color := Token_Type.default; + if (it % word_complete.results.count) == word_complete.selected_result_index { + item_color = Token_Type.warning; + } Simp.prepare_text(font, word_complete.results[it].word); - Simp.draw_prepared_text(font, cast(s64) item_left, cast(s64) item_top, item_color); + Simp.draw_prepared_text(font, cast(s64) item_left, cast(s64) item_top, xx item_color); i+=1; } if (word_complete.scroll_top) { Simp.prepare_text(font_ui_small, BULLET_ICON); - Simp.draw_prepared_text(font_ui_small, xx (rect_left + (rect_w/2)), xx (rect_bottom+rect_h-line_height/2), color = Colors.UI_DEFAULT); + Simp.draw_prepared_text(font_ui_small, xx (rect_left + (rect_w/2)), xx (rect_bottom+rect_h-line_height/2), color = xx Color.UI_DEFAULT); } if (word_complete.results.count > word_complete.scroll_top + max_wc_item) { Simp.prepare_text(font_ui_small, BULLET_ICON); - Simp.draw_prepared_text(font_ui_small, xx (rect_left + (rect_w/2)), xx rect_bottom, color = Colors.UI_DEFAULT); + Simp.draw_prepared_text(font_ui_small, xx (rect_left + (rect_w/2)), xx rect_bottom, color = xx Color.UI_DEFAULT); } } diff --git a/src/keymap.jai b/src/keymap.jai index 139d1b5fb..154689607 100644 --- a/src/keymap.jai +++ b/src/keymap.jai @@ -409,10 +409,11 @@ ACTIONS_EDITORS :: #run arrays_concat(ACTIONS_COMMON, string.[ "move_to_next_buffer", "toggle_line_wrap", "toggle_line_numbers", + "copy_current_line_info", + "word_completion_next", "word_completion_previous", - "word_completion_subword" - "copy_current_line_info", + "word_completion_subword", ]); ACTIONS_OPEN_FILE_DIALOG :: #run arrays_concat(ACTIONS_COMMON, string.[ From 44894cf24291bd360761163bfe4fd955e799791f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Polg=C3=A1r?= Date: Sat, 10 Aug 2024 17:43:31 +0200 Subject: [PATCH 17/17] Smaller box for the word complete result list --- src/editors.jai | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/editors.jai b/src/editors.jai index 3c4b6c2d9..3f130a3b1 100644 --- a/src/editors.jai +++ b/src/editors.jai @@ -3608,8 +3608,8 @@ word_complete_apply :: () { #scope_export Word_Completion :: struct { - DEFAULT_MAX_VISIBLE_ITEM :: 10; - MAX_TOTAL_RESULT :: 35; + DEFAULT_MAX_VISIBLE_ITEM :: 3; + MAX_TOTAL_RESULT :: 30; active := false; should_abort := false;