├── .gitignore ├── LICENSE ├── README.md ├── autoload ├── graphql_client.vim └── graphql_client │ ├── curl.vim │ ├── endpoint.vim │ ├── output.vim │ ├── request.vim │ └── workspace.vim ├── doc └── graphql-client-vim.jax ├── plugin └── graphql_client.vim ├── syntax └── gqlui.vim └── test └── test.graphql /.gitignore: -------------------------------------------------------------------------------- 1 | /doc/tags* 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [2023] [TakuroSugahara] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # graphql-client-vim 2 | 3 | This vim plugin provides graphql client features. Execute requests from a GraphQL file and immediately display the response. 4 | 5 | execute graphql request 6 | 7 | 8 | ## Usage 9 | 10 | - `:GraphQLClientExecute` current buffer (*.graphql) as graphql query. 11 | 12 | ## Installation 13 | 14 | dein 15 | ```dein.toml 16 | [[plugins]] 17 | repo = 'TakuroSugahara/graphql-client-vim' 18 | ``` 19 | 20 | Neobundle 21 | ``` 22 | NeoBundle 'TakuroSugahara/graphql-client-vim' 23 | ``` 24 | 25 | Plug 26 | ``` 27 | Plug 'jparise/vim-graphql' 28 | ``` 29 | 30 | ### setting config 31 | ```vimL 32 | let g:graphql_client_headers = { 33 | \ 'authorization': 'Bearer your token here' 34 | \ } 35 | let g:graphql_client_endpoint = 'http://localhost:8080/api/graphql' 36 | ``` 37 | 38 | ### Requirements 39 | 40 | - [curl](https://github.com/curl/curl) 41 | 42 | ### Want requirements 43 | 44 | - [jq](https://github.com/stedolan/jq) 45 | - Format a GraphQL response in JSON format. 46 | 47 | ### TODO 48 | 49 | - GraphQL schema parsing feature 50 | - Provides auto-completion and error detection capabilities. 51 | -------------------------------------------------------------------------------- /autoload/graphql_client.vim: -------------------------------------------------------------------------------- 1 | let s:graphql_client = {} 2 | let s:graphql_client_instance = {} 3 | 4 | function! s:init() abort 5 | if empty(s:graphql_client_instance) 6 | let s:graphql_client_instance = s:graphql_client.new() 7 | endif 8 | 9 | return s:graphql_client_instance 10 | endfunction 11 | 12 | function! s:graphql_client.new() abort 13 | let s:graphql_client.curl = graphql_client#curl#new(g:graphql_client_headers) 14 | let s:graphql_client.request = graphql_client#request#new() 15 | let s:graphql_client.output = graphql_client#output#new() 16 | let s:graphql_client.endpoint = graphql_client#endpoint#new() 17 | let s:graphql_client.workspace = graphql_client#workspace#new(g:graphql_client_workspaces, s:graphql_client.curl) 18 | return s:graphql_client 19 | endfunction 20 | 21 | function! s:graphql_client.can_exec() abort 22 | let extension = expand('%:e') 23 | if extension != 'graphql' 24 | echoerr "Received *." .extension.". Please should execute *.graphql!" 25 | return 0 26 | endif 27 | return 1 28 | endfunction 29 | 30 | function! graphql_client#execute_request() abort 31 | call s:init() 32 | 33 | if !s:graphql_client.can_exec() 34 | return 35 | endif 36 | 37 | " 現在のファイルのfocusを記憶しておく 38 | let graphql_win_id = win_getid() 39 | 40 | let resp = s:graphql_client.curl.exec_graphql() 41 | call s:graphql_client.output.show() 42 | call s:graphql_client.output.write(split(resp, '\n')) 43 | 44 | call win_gotoid(graphql_win_id) 45 | endfunction 46 | 47 | function! graphql_client#open_ui() abort 48 | call s:init() 49 | 50 | " TODO: 分割表示がうまくいかないのでdadboduiを参考にする 51 | call s:graphql_client.endpoint.show() 52 | call s:graphql_client.request.show() 53 | call s:graphql_client.output.show() 54 | endfunction 55 | 56 | " function! graphql_client#open_endpoint() abort 57 | " call s:init() 58 | " call s:graphql_client.endpoint.show() 59 | " endfunction 60 | 61 | function! graphql_client#set_endpoint() abort 62 | call s:init() 63 | call s:graphql_client.endpoint.set_from_commandline() 64 | endfunction 65 | 66 | function! graphql_client#show_workspace() abort 67 | call s:init() 68 | call s:graphql_client.workspace.show() 69 | endfunction 70 | 71 | -------------------------------------------------------------------------------- /autoload/graphql_client/curl.vim: -------------------------------------------------------------------------------- 1 | let s:curl = {} 2 | 3 | function! graphql_client#curl#new(headers) abort 4 | let s:curl = copy(s:curl) 5 | let s:curl.headers = a:headers 6 | return s:curl 7 | endfunction 8 | 9 | function! s:curl.set_headers(headers) abort 10 | let self.headers = a:headers 11 | endfunction 12 | 13 | function! s:curl.exec_graphql() abort 14 | let headers = self.generate_headers() 15 | let endpoint = self.generate_endpoint() 16 | let body = self.generate_body() 17 | let curl = self.build_curl(endpoint, headers, body) 18 | return system(curl) 19 | endfunction 20 | 21 | function! s:curl.generate_headers() abort 22 | let headers = ["-H 'Content-Type: application/json'"] 23 | for k in keys(self.headers) 24 | let h = "-H '" . k . ": " . self.headers[k] . "'" 25 | let headers = add(headers, h) 26 | endfor 27 | return headers 28 | endfunction 29 | 30 | function! s:curl.generate_endpoint() abort 31 | return g:graphql_client_endpoint 32 | endfunction 33 | 34 | function! s:curl.generate_body() abort 35 | let graphql_file = readfile(expand("%:p")) 36 | " bufnr("%") 37 | let query = join(graphql_file, "") 38 | "NOTE: 引数の文字列に対してエスケープしておかないとparaserがエラーになる" 39 | let query = substitute(query, "\"", '\\\"', 'g') 40 | return json_encode({"query": query}) 41 | endfunction 42 | 43 | function! s:curl.build_curl(endpoint, headers, body) abort 44 | let header = join(a:headers) 45 | 46 | let curl = "curl -s -X POST %E %H -d '%B'" 47 | let curl = substitute(curl, "%E", a:endpoint, '') 48 | let curl = substitute(curl, "%H", header, '') 49 | return substitute(curl, "%B", a:body, '') 50 | endfunction 51 | -------------------------------------------------------------------------------- /autoload/graphql_client/endpoint.vim: -------------------------------------------------------------------------------- 1 | let s:endpoint = {} 2 | 3 | function! graphql_client#endpoint#new() abort 4 | return s:endpoint.new() 5 | endfunction 6 | 7 | function! s:endpoint.new() abort 8 | let s:endpoint = copy(s:endpoint) 9 | let s:endpoint.buffer_name = 'graphql_client_endpoint' 10 | return s:endpoint 11 | endfunction 12 | 13 | function! s:endpoint.show() abort 14 | call self.open_buffer() 15 | call self.setup_buffer() 16 | endfunction 17 | 18 | function! s:endpoint.set_from_commandline() abort 19 | let input_endpoint = input('Graphql Endpoint URL: ') 20 | let g:graphql_client_endpoint = input_endpoint 21 | echo "Setting graphql endpoint: " . g:graphql_client_endpoint 22 | endfunction 23 | 24 | function! s:endpoint.open_buffer() abort 25 | let buffer_win = bufwinid(self.buffer_name) 26 | if buffer_win > -1 27 | call win_gotoid(buffer_win) 28 | else 29 | execute ":horizontal leftabove split " . self.buffer_name 30 | endif 31 | endfunction 32 | 33 | function! s:endpoint.setup_buffer() abort 34 | silent 1,$delete _ 35 | call setline("1", g:graphql_client_endpoint) 36 | resize 2 37 | " setlocal buftype=nofile 38 | setlocal bufhidden=wipe 39 | setlocal noswapfile 40 | setlocal hidden 41 | endfunction 42 | 43 | -------------------------------------------------------------------------------- /autoload/graphql_client/output.vim: -------------------------------------------------------------------------------- 1 | let s:output = {} 2 | 3 | function! graphql_client#output#new() abort 4 | return s:output.new() 5 | endfunction 6 | 7 | function! s:output.new() abort 8 | let s:output = copy(s:output) 9 | let s:output.buffer_name = 'output.json' 10 | let s:output.exist_jq = system('jq -h &> /dev/null && echo 0 || echo 1') == 0 11 | return s:output 12 | endfunction 13 | 14 | function! s:output.show() abort 15 | call self.open_buffer() 16 | call self.setup_buffer() 17 | endfunction 18 | 19 | function! s:output.write(strings) abort 20 | silent 1,$delete _ 21 | call setline("1", a:strings) 22 | 23 | "---------- jqコマンドがあればformat ---------------" 24 | if self.exist_jq 25 | :%!jq '.' 26 | endif 27 | "---------- jqコマンドがあればformat ---------------" 28 | endfunction 29 | 30 | function! s:output.open_buffer() abort 31 | let buffer_win = bufwinid(self.buffer_name) 32 | if buffer_win > -1 33 | call win_gotoid(buffer_win) 34 | else 35 | execute "botright vnew " . self.buffer_name 36 | endif 37 | endfunction 38 | 39 | function! s:output.setup_buffer() abort 40 | setlocal buftype=nofile 41 | setlocal bufhidden=wipe 42 | setlocal noswapfile 43 | setlocal hidden 44 | endfunction 45 | -------------------------------------------------------------------------------- /autoload/graphql_client/request.vim: -------------------------------------------------------------------------------- 1 | let s:request = {} 2 | 3 | function! graphql_client#request#new() abort 4 | return s:request.new() 5 | endfunction 6 | 7 | function! s:request.new() abort 8 | let s:request = copy(s:request) 9 | let s:request.buffer_name = 'request.graphql' 10 | return s:request 11 | endfunction 12 | 13 | function! s:request.show() abort 14 | call self.open_buffer() 15 | call self.setup_buffer() 16 | endfunction 17 | 18 | function! s:request.open_buffer() abort 19 | let buffer_win = bufwinid(self.buffer_name) 20 | if buffer_win > -1 21 | call win_gotoid(buffer_win) 22 | else 23 | " 現在のバッファと置き換えるようにバッファを作成 24 | " execute \":topleft vnew \" . self.buffer_name 25 | execute "e " . self.buffer_name 26 | endif 27 | endfunction 28 | 29 | function! s:request.setup_buffer() abort 30 | silent 1,$delete _ 31 | setlocal buftype=nofile 32 | setlocal bufhidden=wipe 33 | setlocal noswapfile 34 | setlocal hidden 35 | endfunction 36 | -------------------------------------------------------------------------------- /autoload/graphql_client/workspace.vim: -------------------------------------------------------------------------------- 1 | let s:workspace = {} 2 | 3 | function! graphql_client#workspace#new(workspaces, curl) abort 4 | return s:workspace.new(a:workspaces, a:curl) 5 | endfunction 6 | 7 | function! s:workspace.new(workspaces, curl) abort 8 | let s:workspace = copy(s:workspace) 9 | let s:workspace.buffer_name = 'gqlui' 10 | let s:workspace.workspaces = a:workspaces 11 | let s:workspace.curl = a:curl 12 | let s:workspace.current_workspace_key = len(a:workspaces) > 0 ? keys(a:workspaces)[0] : '' 13 | let s:workspace.icons = g:graphql_client_icons 14 | call s:workspace.set_current_workspace_from_key(s:workspace.current_workspace_key) 15 | return s:workspace 16 | endfunction 17 | 18 | function! s:workspace.show() abort 19 | call self.open_buffer() 20 | call self.setup_buffer() 21 | endfunction 22 | 23 | function! s:workspace.open_buffer() abort 24 | let buffer_win = bufwinid(self.buffer_name) 25 | if buffer_win > -1 26 | call win_gotoid(buffer_win) 27 | else 28 | execute "topleft vnew " . self.buffer_name 29 | endif 30 | endfunction 31 | 32 | function! s:workspace.setup_buffer() abort 33 | vertical-resize 40 34 | setlocal filetype=gqlui 35 | setlocal buftype=nofile 36 | setlocal bufhidden=wipe 37 | setlocal noswapfile 38 | setlocal hidden 39 | 40 | nnoremap :call method('set_current_workspace') 41 | nnoremap ? :call method('show_workspace_info') 42 | 43 | call self.redraw() 44 | setlocal nomodifiable 45 | endfunction 46 | 47 | function! s:workspace.redraw() abort 48 | setlocal modifiable 49 | " clear file 50 | silent 1,$delete _ 51 | 52 | " write workspaces 53 | call setline(1, '" Press Enter for set endpoint') 54 | call setline(2, '') 55 | 56 | let i = 3 57 | for k in keys(self.workspaces) 58 | let workspace_name = k 59 | if self.current_workspace_key == k 60 | let workspace_name = k.' '.self.icons.current_workspace 61 | endif 62 | call setline(i, workspace_name) 63 | 64 | let i += 1 65 | endfor 66 | 67 | setlocal nomodifiable 68 | endfunction 69 | 70 | function! s:workspace.show_workspace_info() abort 71 | let content = matchstr(getline('.'), '\S\+') 72 | echo self.get_workspace_info(content) 73 | endfunction 74 | 75 | function! s:workspace.get_workspace_info(key) abort 76 | if !has_key(self.workspaces, a:key) 77 | return 'not found workspace info' 78 | endif 79 | return self.workspaces[a:key] 80 | endfunction 81 | 82 | function! s:workspace.set_current_workspace() abort 83 | let content = matchstr(getline('.'), '\S\+') 84 | call self.set_current_workspace_from_key(content) 85 | endfunction 86 | 87 | function! s:workspace.set_current_workspace_from_key(key) abort 88 | for k in keys(self.workspaces) 89 | if a:key == k 90 | let self.current_workspace_key = k 91 | let workspace_info = self.get_workspace_info(k) 92 | let g:graphql_client_endpoint = workspace_info.endpoint 93 | call self.curl.set_headers(workspace_info.headers) 94 | 95 | call self.redraw() 96 | echo 'set '.self.current_workspace_key.' workspace' 97 | return 98 | endif 99 | endfor 100 | endfunction 101 | 102 | function! s:method(method_name) abort 103 | return s:workspace[a:method_name]() 104 | endfunction 105 | -------------------------------------------------------------------------------- /doc/graphql-client-vim.jax: -------------------------------------------------------------------------------- 1 | *graphql-client-vim.txt* 2 | 3 | GraphQL Client for https://github.com/TakuroSugahara/graphql-client-vim 4 | 5 | Author : TakuroSugahara 6 | License : MIT license {{{ 7 | Permission is hereby granted, free of charge, to any person obtaining 8 | a copy of this software and associated documentation files (the 9 | "Software"), to deal in the Software without restriction, including 10 | without limitation the rights to use, copy, modify, merge, publish, 11 | distribute, sublicense, and/or sell copies of the Software, and to 12 | permit persons to whom the Software is furnished to do so, subject to 13 | the following conditions: 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 21 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | }}} 25 | 26 | ============================================================================== 27 | CONTENTS *graphql-client-vim-contents* 28 | 29 | INTRODUCTION |graphql-client-vim-introduction| 30 | USAGE |graphql-client-vim-usage| 31 | INTERFACE |graphql-client-vim-interface| 32 | VARIABLES |graphql-client-vim-variables| 33 | COMMANDS |graphql-client-vim-commands| 34 | FUNCTIONS |graphql-client-vim-functions| 35 | TODO |graphql-client-vim-todo| 36 | CHANGELOG |graphql-client-vim-changelog| 37 | 38 | 39 | ============================================================================== 40 | INTRODUCTION *graphql-client-vim-introduction* 41 | 42 | *graphql-client-vim.vim*provides graphql client features. 43 | Execute requests from a GraphQL file and immediately display the response. 44 | 45 | Latest version: 46 | https://github.com/user/graphql-client-vim.vim 47 | 48 | 49 | ============================================================================== 50 | USAGE *graphql-client-vim-usage* 51 | 52 | 53 | 54 | ============================================================================== 55 | INTERFACE *graphql-client-vim-interface* 56 | 57 | ------------------------------------------------------------------------------ 58 | VARIABLES *graphql-client-vim-variables* 59 | 60 | g:graphql_client_endpoint *g:graphql_client_endpoint* 61 | Default value: "" 62 | 63 | 64 | g:graphql_client_headers *g:graphql_client_headers* 65 | Default value: {} 66 | 67 | 68 | ------------------------------------------------------------------------------ 69 | COMMANDS *graphql-client-vim-commands* 70 | 71 | :GraphQLClientExecute *:GraphQLClientExecute* 72 | current buffer (*.graphql) as graphql query. 73 | 74 | ------------------------------------------------------------------------------ 75 | FUNCTIONS *graphql-client-vim-functions* 76 | 77 | ============================================================================== 78 | TODO *graphql-client-vim-todo* 79 | 80 | 81 | ============================================================================== 82 | CHANGELOG *graphql-client-vim-changelog* 83 | 84 | 85 | ============================================================================== 86 | vim:tw=78:ts=8:ft=help:norl:noet:fen: 87 | -------------------------------------------------------------------------------- /plugin/graphql_client.vim: -------------------------------------------------------------------------------- 1 | if exists("g:loaded_graphql_client") 2 | finish 3 | endif 4 | let g:loaded_graphql_client = 1 5 | 6 | let g:graphql_client_endpoint = get(g:, 'graphql_client_endpoint', '') 7 | let g:graphql_client_workspaces = get(g:, 'graphql_client_workspaces', {}) 8 | let g:graphql_client_headers = get(g:, 'graphql_client_headers', {}) 9 | let g:graphql_client_headers = get(g:, 'graphql_client_headers', {}) 10 | let g:graphql_client_icons = get(g:, 'graphql_client_icons', { 11 | \ 'current_workspace': '✓' 12 | \}) 13 | 14 | augroup GraphqlClient 15 | autocmd! 16 | autocmd FileType gqlui autocmd BufEnter,WinEnter stopinsert 17 | augroup END 18 | 19 | " Execute graphql request 20 | command! -nargs=0 GQLExecute call graphql_client#execute_request() 21 | " Set endpoint url 22 | command! -nargs=0 GQLSetEndpoint call graphql_client#set_endpoint() 23 | " Show graphql workspace 24 | command! -nargs=0 GQLShowWorkSpace call graphql_client#show_workspace() 25 | 26 | -------------------------------------------------------------------------------- /syntax/gqlui.vim: -------------------------------------------------------------------------------- 1 | syntax clear 2 | 3 | exe 'syn match gqlui_current_workspace /'.g:graphql_client_icons.current_workspace.'/' 4 | syn match graphql_client_comment /^".*$/ 5 | hi default link graphql_client_comment Comment 6 | if &background ==? 'light' 7 | hi gqlui_current_workspace guifg=#00AA00 8 | else 9 | hi gqlui_current_workspace guifg=#88FF88 10 | endif 11 | 12 | -------------------------------------------------------------------------------- /test/test.graphql: -------------------------------------------------------------------------------- 1 | query findOneUser { 2 | user(id: "user-1") { 3 | id 4 | name 5 | createdAt 6 | updatedAt 7 | } 8 | } 9 | --------------------------------------------------------------------------------