parent
56306b095e
commit
e78a5032dc
|
@ -588,12 +588,30 @@ in {
|
||||||
src = ./packages/change-case.el;
|
src = ./packages/change-case.el;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
tclip = {
|
||||||
|
enable = true;
|
||||||
|
after = [ "request" ];
|
||||||
|
package = (epkgs: epkgs.trivialBuild {
|
||||||
|
pname = "tclip";
|
||||||
|
src = ./packages/tclip.el;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
xe-chatgpt = {
|
||||||
|
enable = true;
|
||||||
|
after = [ "request" ];
|
||||||
|
package = (epkgs: epkgs.trivialBuild {
|
||||||
|
pname = "xe-chatgpt";
|
||||||
|
src = ./packages/xe-chatgpt.el;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
xe-tools = {
|
xe-tools = {
|
||||||
enable = true;
|
enable = true;
|
||||||
package = (epkgs: epkgs.trivialBuild {
|
package = (epkgs: epkgs.trivialBuild {
|
||||||
pname = "xe-tools";
|
pname = "xe-tools";
|
||||||
src = ./xe-tools.el;
|
src = ./packages/xe-tools.el;
|
||||||
});
|
});
|
||||||
|
|
||||||
config = ''
|
config = ''
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
;;; tclip.el --- tclip client for Emacs -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
;; Copyright (C)
|
||||||
|
;; 2023 Tailscale, Inc.
|
||||||
|
;; Author: Xe Iaso <xe@tailscale.com>
|
||||||
|
;; Maintainer: Xe Iaso <xe@tailscale.com>
|
||||||
|
;; Created: 2023-01-13
|
||||||
|
;; Version: 0.1
|
||||||
|
;; Keywords: tailscale, pastebin, sharing
|
||||||
|
;; Homepage: https://github.com/tailscale-dev/tclip
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
;;
|
||||||
|
;; This uses request-el to make requests to your tailnet's tclip server. You
|
||||||
|
;; can install request-el with M-x package-install.
|
||||||
|
;;
|
||||||
|
;; This package requires that you have a tclip server set up. This package
|
||||||
|
;; reaches out to a tclip server over either plain HTTP, or HTTPS should you
|
||||||
|
;; configure the variable `tclip-server'.
|
||||||
|
;;
|
||||||
|
;; Usage:
|
||||||
|
;;
|
||||||
|
;; To submit the contents of the current buffer to tclip:
|
||||||
|
;; M-x tclip-submit-buffer
|
||||||
|
;; To submit the contents of the currently highlighted region to tclip:
|
||||||
|
;; M-x tclip-submit-region
|
||||||
|
;;
|
||||||
|
;; Customization:
|
||||||
|
;;
|
||||||
|
;; To customize the tclip server this package reaches out to:
|
||||||
|
;; M-x customize-group tclip
|
||||||
|
;;
|
||||||
|
;; You can customize the tclip server URL by changing the value of `tclip-server':
|
||||||
|
;; (setq tclip-server "https://paste.shark-harmonic.ts.net")
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(require 'request)
|
||||||
|
|
||||||
|
(defgroup tclip nil
|
||||||
|
"Tclip server configuration."
|
||||||
|
:prefix "tclip-"
|
||||||
|
:group 'tclip)
|
||||||
|
|
||||||
|
(defcustom tclip-server "http://paste"
|
||||||
|
"The server that is running tclip or a service with a compatible API to tclip. This should NOT end with a trailing slash."
|
||||||
|
:group 'tclip
|
||||||
|
:type 'string)
|
||||||
|
|
||||||
|
(defun tclip--send-paste (fname content)
|
||||||
|
"Internal function that actually fires off the paste with name FNAME and content CONTENT to the tclip server."
|
||||||
|
(request (format "%s/api/post" tclip-server)
|
||||||
|
:type "POST"
|
||||||
|
:data `(("filename" . ,fname)
|
||||||
|
("content" . ,content))
|
||||||
|
:headers '(("Accept" . "text/plain"))
|
||||||
|
:timeout 60
|
||||||
|
:success (cl-function
|
||||||
|
(lambda (&key response &allow-other-keys)
|
||||||
|
(message "%s" (request-response-data response))))))
|
||||||
|
|
||||||
|
(defun tclip-submit-buffer ()
|
||||||
|
"Submits the entire current buffer to tclip."
|
||||||
|
(interactive)
|
||||||
|
(let ((fname (format "%s.%s"
|
||||||
|
(file-name-base (buffer-file-name))
|
||||||
|
(file-name-extension (buffer-file-name))))
|
||||||
|
(content (buffer-string)))
|
||||||
|
(tclip--send-paste fname content)))
|
||||||
|
|
||||||
|
(defun tclip-submit-region ()
|
||||||
|
"Submits the highlighted region to tclip."
|
||||||
|
(interactive)
|
||||||
|
(let ((fname (format "%s.%s"
|
||||||
|
(file-name-base (buffer-file-name))
|
||||||
|
(file-name-extension (buffer-file-name))))
|
||||||
|
(content (buffer-substring-no-properties (region-beginning) (region-end))))
|
||||||
|
(tclip--send-paste fname content)))
|
||||||
|
|
||||||
|
(provide 'tclip)
|
||||||
|
;;; tclip.el ends here
|
|
@ -0,0 +1,73 @@
|
||||||
|
;;; xe-tools --- Xe's chatgpt bindings
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
|
||||||
|
;;; I guess we're gonna have to deal with this shit,
|
||||||
|
;;; so I might as well try and learn how to use it.
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(setf lexical-binding t)
|
||||||
|
(eval-when-compile '(require 'cl))
|
||||||
|
|
||||||
|
(require 'request)
|
||||||
|
|
||||||
|
(defcustom xe/chatgpt-base-prompt
|
||||||
|
"You are an assistant that helps Xe Iaso with programming. You will return answers and code that helps Xe program things."
|
||||||
|
"The default system message for ChatGPT."
|
||||||
|
:type 'string)
|
||||||
|
|
||||||
|
(defun xe/chatgpt--chomp (str)
|
||||||
|
"Chomp leading and tailing whitespace from STR."
|
||||||
|
(while (string-match "\\`\n+\\|^\\s-+\\|\\s-+$\\|\n+\\'"
|
||||||
|
str)
|
||||||
|
(setq str (replace-match "" t t str)))
|
||||||
|
str)
|
||||||
|
|
||||||
|
(defun xe/chatgpt--read-file (fname)
|
||||||
|
"Reads FNAME and returns its contents as a string."
|
||||||
|
(with-temp-buffer
|
||||||
|
(insert-file-contents fname)
|
||||||
|
(xe/chatgpt--chomp (buffer-string))))
|
||||||
|
|
||||||
|
(defun xe/chatgpt--make-request (question)
|
||||||
|
"Internal function to ask ChatGPT a QUESTION and insert the result text of the first response to the current buffer."
|
||||||
|
(let* ((req `(("model" . "gpt-3.5-turbo")
|
||||||
|
("messages" . ((("role" . "system") ("content" . ,xe/chatgpt-base-prompt))
|
||||||
|
(("role" . "user") ("content" . ,question))))))
|
||||||
|
(auth-key (xe/chatgpt--read-file
|
||||||
|
(format "%s/.openai-token" (getenv "HOME"))))
|
||||||
|
(headers `(("Content-Type" . "application/json")
|
||||||
|
("Authorization" . ,(format "Bearer %s" auth-key)))))
|
||||||
|
(request
|
||||||
|
"https://api.openai.com/v1/chat/completions"
|
||||||
|
:type "POST"
|
||||||
|
:data (json-encode req)
|
||||||
|
:headers headers
|
||||||
|
:parser 'json-read
|
||||||
|
:encoding 'utf-8
|
||||||
|
:success (cl-function
|
||||||
|
(lambda (&key data &allow-other-keys)
|
||||||
|
(message "%S" data)
|
||||||
|
(let* ((choice (aref (alist-get 'choices data) 0))
|
||||||
|
(message (alist-get 'message choice))
|
||||||
|
(content (alist-get 'content message)))
|
||||||
|
(message "ChatGPT reply: %s" content)
|
||||||
|
(insert content)))))))
|
||||||
|
|
||||||
|
(defun xe/chatgpt-ask (question)
|
||||||
|
"Ask ChatGPT a QUESTION and get the response put into your current buffer."
|
||||||
|
(interactive "squestion> ")
|
||||||
|
(message "ChatGPT ask: %s" question)
|
||||||
|
(xe/chatgpt--make-request prompt))
|
||||||
|
|
||||||
|
(defun xe/chatgpt-ask-with-mode (question)
|
||||||
|
"Ask ChatGPT a QUESTION and get the response put into your current buffer. This will add the context of what editor major mode you are in."
|
||||||
|
(interactive "squestion> ")
|
||||||
|
(message "ChatGPT ask: %s" question)
|
||||||
|
(let* ((editor-mode (string-join (split-string (symbol-name major-mode) "-") " "))
|
||||||
|
(prompt (format "%s\nUser is in %s. Only include the code." question editor-mode)))
|
||||||
|
(xe/chatgpt--make-request prompt)))
|
||||||
|
|
||||||
|
(provide 'xe-chatgpt)
|
||||||
|
;;; xe-chatgpt.el ends here
|
Loading…
Reference in New Issue