Skip to content

Instantly share code, notes, and snippets.

@merisbahti
Created December 26, 2024 19:49
Show Gist options
  • Save merisbahti/436e63bab36731c021724c1d681a680f to your computer and use it in GitHub Desktop.
Save merisbahti/436e63bab36731c021724c1d681a680f to your computer and use it in GitHub Desktop.
ai hints plugin for steel
(require (prefix-in helix. "helix/commands.scm"))
(require (prefix-in helix.static. "helix/static.scm"))
(require "helix/misc.scm")
(require "component.scm")
(require "helix/editor.scm")
(require-builtin helix/components)
(require-builtin helix/core/text as text.)
(require "cogs/helix-ext.scm")
(define (run-cmd cmd . args)
(let
([builder (command cmd args)])
(set-piped-stdout! builder)
(~> builder spawn-process Ok->value wait->stdout Ok->value)))
(define api-key (trim (run-cmd "printenv" "OPENAI_API_KEY")))
(define (get-document-as-slice)
(let* ([focus (editor-focus)]
[focus-doc-id (editor->doc-id focus)])
(text.rope->string (editor->text focus-doc-id))))
(define openapi-server "https://api.openai.com/v1/chat/completions")
(define (make-request code-with-cursor callback)
(spawn-native-thread
(fn ()
(define output
(run-cmd
"curl"
openapi-server
"-d"
(value->jsexpr-string
(hash
'model
"gpt-4o-mini"
'messages
(list
(hash
'role
"user"
'content
(string-join
(list "Only answer in code without wrapping into markdown, what would you put at the position of <CURSOR>, don't include text before or after <CURSOR>:
"
code-with-cursor))))
'prediction
(hash 'type "content" 'content code-with-cursor)
'temperature
0.1))
"-H"
"Content-Type: application/json"
"-H"
(string-join (list "Authorization: Bearer " api-key))))
(define parsed-output
(~>
(string->jsexpr output)
(hash-ref 'choices)
(list-ref 0)
(hash-ref 'message)
(hash-ref 'content)))
(hx.with-context
(fn ()
(callback parsed-output))))))
(define *latest-inlay-hint* (None))
(provide ask-prompt)
(provide accept-current-hint)
;; accepts the current ai generated hint
(define (accept-current-hint)
(when (not (None? *latest-inlay-hint*))
(helix.static.insert_string (cadr *latest-inlay-hint*))
(clear-inlay-hint)))
(define (clear-inlay-hint)
(when (not (None? *latest-inlay-hint*))
(apply remove-inlay-hint (cons *helix.cx* *latest-inlay-hint*))
(set! *latest-inlay-hint* (None))))
;; each character should'nt send a request
(define *latest-debounce-id* 0)
(define (ask-prompt)
(define current-debounce-id (+ 1 *latest-debounce-id*))
(set! *latest-debounce-id* current-debounce-id)
(define doc (get-document-as-slice))
(define cursor-pos (hx.cx->pos))
(define code-with-cursor
(string-join
(list
(substring doc 0 cursor-pos)
"<CURSOR>"
(substring doc cursor-pos))))
(enqueue-thread-local-callback-with-delay 300
(fn ()
(when
(not (equal? current-debounce-id *latest-debounce-id*))
(return! void))
(make-request code-with-cursor
(fn (x)
(when (not (equal? current-debounce-id *latest-debounce-id*)) (return! void))
(hx.with-context
(fn ()
(clear-inlay-hint)
(set! *latest-inlay-hint* (list cursor-pos x))
(add-inlay-hint *helix.cx* cursor-pos x))))))))
(register-hook! "post-command"
(fn (_)
(clear-inlay-hint)))
(register-hook! "post-insert-char"
(fn (_)
(clear-inlay-hint)
(ask-prompt)))
(register-hook! "on-mode-switch"
(fn (_)
(set! *latest-debounce-id* (+ 1 *latest-debounce-id*))
(clear-inlay-hint)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment