├── LICENSE ├── README.md ├── denops └── @ddc-sources │ └── copilot.ts ├── doc └── ddc-source-copilot.txt └── lua └── ddc └── source └── copilot.lua /LICENSE: -------------------------------------------------------------------------------- 1 | MIT license 2 | 3 | Copyright (c) Shougo Matsushita 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included 14 | in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ddc-source-copilot 2 | 3 | Copilot completion for ddc.vim 4 | 5 | NOTE: It is based on "ddc-copilot". 6 | 7 | https://github.com/yuki-yano/ddc-copilot 8 | 9 | ## Required 10 | 11 | ### copilot.vim or copilot.lua 12 | 13 | https://github.com/github/copilot.vim 14 | 15 | https://github.com/zbirenbaum/copilot.lua 16 | 17 | ### denops.vim 18 | 19 | https://github.com/vim-denops/denops.vim 20 | 21 | ### ddc.vim 22 | 23 | https://github.com/Shougo/ddc.vim 24 | 25 | ## Configuration 26 | 27 | ```vim 28 | let g:copilot_no_maps = v:true 29 | 30 | call ddc#custom#patch_global('sources', ['copilot']) 31 | 32 | call ddc#custom#patch_global('sourceOptions', #{ 33 | \ copilot: #{ 34 | \ mark: 'copilot', 35 | \ matchers: [], 36 | \ minAutoCompleteLength: 0, 37 | \ } 38 | \ }) 39 | call ddc#custom#patch_global('sourceParams', #{ 40 | \ copilot: #{ 41 | \ copilot: 'vim', 42 | \ } 43 | \ }) 44 | ``` 45 | -------------------------------------------------------------------------------- /denops/@ddc-sources/copilot.ts: -------------------------------------------------------------------------------- 1 | import { type DdcGatherItems } from "jsr:@shougo/ddc-vim@~9.4.0/types"; 2 | import { 3 | BaseSource, 4 | type GatherArguments, 5 | type OnCompleteDoneArguments, 6 | type OnInitArguments, 7 | } from "jsr:@shougo/ddc-vim@~9.4.0/source"; 8 | import { 9 | Unprintable, 10 | type UnprintableUserData, 11 | } from "jsr:@milly/ddc-unprintable@~5.0.0"; 12 | import { assert, is } from "jsr:@core/unknownutil@~4.3.0"; 13 | 14 | import type { Denops } from "jsr:@denops/core@~7.0.0"; 15 | import * as fn from "jsr:@denops/std@~7.5.0/function"; 16 | import { batch } from "jsr:@denops/std@~7.5.0/batch"; 17 | import { register } from "jsr:@denops/std@~7.5.0/lambda"; 18 | import { delay } from "jsr:@std/async@~1.0.4/delay"; 19 | 20 | type Suggestion = { 21 | displayText: string; 22 | position: { 23 | character: number; 24 | line: number; 25 | }; 26 | range: { 27 | start: { 28 | character: number; 29 | line: number; 30 | }; 31 | end: { 32 | character: number; 33 | line: number; 34 | }; 35 | }; 36 | insertText: string; 37 | uuid: string; 38 | }; 39 | 40 | type Params = { 41 | copilot: "vim" | "lua"; 42 | }; 43 | type UserData = Record & UnprintableUserData; 44 | 45 | export class Source extends BaseSource { 46 | #unprintable?: Unprintable; 47 | 48 | override onInit(_args: OnInitArguments) { 49 | this.#unprintable = new Unprintable({ 50 | highlightGroup: "SpecialKey", 51 | callbackId: `source/${this.name}`, 52 | }); 53 | } 54 | 55 | override async gather( 56 | args: GatherArguments, 57 | ): Promise { 58 | switch (args.sourceParams.copilot) { 59 | case "vim": { 60 | if (!await fn.exists(args.denops, "*copilot#Complete")) { 61 | return []; 62 | } 63 | 64 | this.#tellToVim(args); 65 | break; 66 | } 67 | case "lua": { 68 | if (args.denops.meta.host !== "nvim") { 69 | return []; 70 | } 71 | 72 | this.#tellToLua(args); 73 | break; 74 | } 75 | default: { 76 | args.sourceParams.copilot satisfies never; 77 | break; 78 | } 79 | } 80 | 81 | return await Promise.resolve({ 82 | items: [], 83 | isIncomplete: true, 84 | }); 85 | } 86 | 87 | override params(): Params { 88 | // NOTE: use vim as default for compatibility 89 | return { 90 | copilot: "vim", 91 | }; 92 | } 93 | 94 | override onCompleteDone( 95 | args: OnCompleteDoneArguments, 96 | ): Promise { 97 | return this.#unprintable!.onCompleteDone(args); 98 | } 99 | 100 | async #tellToVim( 101 | args: GatherArguments, 102 | ): Promise { 103 | await batch(args.denops, async (denops: Denops) => { 104 | await denops.call("copilot#Suggest"); 105 | await denops.call("copilot#Next"); 106 | await denops.call("copilot#Previous"); 107 | }); 108 | 109 | while (!await fn.exists(args.denops, "b:_copilot.suggestions")) { 110 | await delay(10); 111 | } 112 | 113 | const suggestions = await args.denops.call( 114 | "eval", 115 | "b:_copilot.suggestions", 116 | ) as Suggestion[]; 117 | 118 | await this.#updateItems(args, suggestions); 119 | } 120 | 121 | async #tellToLua( 122 | args: GatherArguments, 123 | ): Promise { 124 | const id = register(args.denops, async (suggestions: unknown) => { 125 | assert(suggestions, is.ArrayOf(is.ObjectOf({ text: is.String }))); 126 | 127 | await this.#updateItems( 128 | args, 129 | suggestions.map(({ text: insertText }) => ({ insertText })), 130 | ); 131 | }); 132 | 133 | await args.denops.call( 134 | "luaeval", 135 | "require('ddc.source.copilot').update_items(_A[1], _A[2])", 136 | [args.denops.name, id], 137 | ); 138 | } 139 | 140 | async #updateItems( 141 | args: GatherArguments, 142 | suggestions: Pick[], 143 | ): Promise { 144 | const items = suggestions.map(({ insertText }) => { 145 | const match = /^(?\s*).+/.exec(insertText); 146 | const indent = match?.groups?.indent; 147 | 148 | const info = indent != null 149 | ? insertText.split("\n").map((line) => line.slice(indent.length)) 150 | .join("\n") 151 | : insertText; 152 | 153 | return { 154 | word: insertText.slice(args.completePos), 155 | info, 156 | }; 157 | }); 158 | 159 | await args.denops.call( 160 | "ddc#update_items", 161 | this.name, 162 | await this.#unprintable!.convertItems( 163 | args.denops, 164 | items, 165 | args.context.nextInput, 166 | ), 167 | ); 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /doc/ddc-source-copilot.txt: -------------------------------------------------------------------------------- 1 | *ddc-source-copilot.txt* copilot completion for ddc.vim 2 | 3 | Author: Shougo 4 | License: MIT license 5 | 6 | CONTENTS *ddc-source-copilot-contents* 7 | 8 | Introduction |ddc-source-copilot-introduction| 9 | Install |ddc-source-copilot-install| 10 | Examples |ddc-source-copilot-examples| 11 | FAQ |ddc-source-copilot-faq| 12 | 13 | 14 | ============================================================================== 15 | INTRODUCTION *ddc-source-copilot-introduction* 16 | 17 | This source collects items from github Copilot. 18 | 19 | NOTE: It is based on "ddc-copilot". 20 | 21 | https://github.com/yuki-yano/ddc-copilot 22 | 23 | 24 | ============================================================================== 25 | INSTALL *ddc-source-copilot-install* 26 | 27 | Please install both "copilot.vim" (or "copilot.lua"), "ddc.vim" and 28 | "denops.vim". 29 | 30 | https://github.com/github/copilot.vim 31 | https://github.com/zbirenbaum/copilot.lua 32 | https://github.com/Shougo/ddc.vim 33 | https://github.com/vim-denops/denops.vim 34 | 35 | 36 | ============================================================================== 37 | PARAMS *ddc-source-copilot-params* 38 | 39 | *ddc-source-copilot-param-copilot* 40 | copilot ("vim"|"lua") 41 | Types of Copilot integration to use. 42 | "vim": Use copilot.vim 43 | "lua": Use copilot.lua(Nvim only) 44 | 45 | Default: "vim" 46 | 47 | ============================================================================== 48 | EXAMPLES *ddc-source-copilot-examples* 49 | >vim 50 | let g:copilot_no_maps = v:true 51 | 52 | call ddc#custom#patch_global('sources', ['copilot']) 53 | 54 | call ddc#custom#patch_global('sourceOptions', #{ 55 | \ copilot: #{ 56 | \ matchers: [], 57 | \ mark: 'copilot', 58 | \ minAutoCompleteLength: 0, 59 | \ } 60 | \ }) 61 | call ddc#custom#patch_global('sourceParams', #{ 62 | \ copilot: #{ 63 | \ copilot: 'vim', 64 | \ } 65 | \ }) 66 | < 67 | 68 | ============================================================================== 69 | FAQ *ddc-source-copilot-faq* 70 | 71 | Q: The items is not updated or generated. 72 | 73 | A: They are not updated if cached. It is performance reason. You can refresh 74 | them by |ddc#map#manual_complete()| manually. 75 | 76 | ============================================================================== 77 | vim:tw=78:ts=8:ft=help:norl:noet:fen:noet: 78 | -------------------------------------------------------------------------------- /lua/ddc/source/copilot.lua: -------------------------------------------------------------------------------- 1 | local api = require("copilot.api") 2 | local util = require("copilot.util") 3 | local client = require("copilot.client") 4 | 5 | local M = {} 6 | 7 | --- Update completion items 8 | --- @param name string 9 | --- @param lambda_id string 10 | M.update_items = function(name, lambda_id) 11 | local c = client.get() 12 | if c == nil then 13 | return 14 | end 15 | api.get_completions(c, util.get_doc_params(), function(err, response) 16 | if err or not response or not response.completions or #response.completions == 0 then 17 | return 18 | end 19 | vim.fn["denops#notify"](name, lambda_id, { response.completions }) 20 | end) 21 | end 22 | 23 | return M 24 | --------------------------------------------------------------------------------