@gradio/code 0.11.2 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # @gradio/code
2
2
 
3
+ ## 0.13.0
4
+
5
+ ### Features
6
+
7
+ - [#10812](https://github.com/gradio-app/gradio/pull/10812) [`6384bcc`](https://github.com/gradio-app/gradio/commit/6384bcc11f13d22f4480e7ad7213486fecec8936) - Jedi-based Python code completion on `gr.Code`. Thanks @whitphx!
8
+
9
+ ### Dependency updates
10
+
11
+ - @gradio/atoms@0.14.1
12
+ - @gradio/statustracker@0.10.6
13
+ - @gradio/wasm@0.18.0
14
+ - @gradio/upload@0.15.6
15
+
16
+ ## 0.12.0
17
+
18
+ ### Features
19
+
20
+ - [#10733](https://github.com/gradio-app/gradio/pull/10733) [`731ab92`](https://github.com/gradio-app/gradio/commit/731ab92001c88d4cf1062acf0a4f1108a4513014) - Autocompletion on code editor component. Thanks @whitphx!
21
+
22
+ ### Dependency updates
23
+
24
+ - @gradio/upload@0.15.5
25
+ - @gradio/statustracker@0.10.5
26
+ - @gradio/atoms@0.14.0
27
+
3
28
  ## 0.11.2
4
29
 
5
30
  ### Dependency updates
package/Index.svelte CHANGED
@@ -40,6 +40,7 @@
40
40
  export let min_width: number | undefined = undefined;
41
41
  export let wrap_lines = false;
42
42
  export let show_line_numbers = true;
43
+ export let autocomplete = false;
43
44
 
44
45
  export let interactive: boolean;
45
46
 
@@ -93,6 +94,7 @@
93
94
  {dark_mode}
94
95
  {wrap_lines}
95
96
  {show_line_numbers}
97
+ {autocomplete}
96
98
  readonly={!interactive}
97
99
  on:blur={() => gradio.dispatch("blur")}
98
100
  on:focus={() => gradio.dispatch("focus")}
package/dist/Index.svelte CHANGED
@@ -27,6 +27,7 @@ export let scale = null;
27
27
  export let min_width = void 0;
28
28
  export let wrap_lines = false;
29
29
  export let show_line_numbers = true;
30
+ export let autocomplete = false;
30
31
  export let interactive;
31
32
  let dark_mode = gradio.theme === "dark";
32
33
  function handle_change() {
@@ -78,6 +79,7 @@ $:
78
79
  {dark_mode}
79
80
  {wrap_lines}
80
81
  {show_line_numbers}
82
+ {autocomplete}
81
83
  readonly={!interactive}
82
84
  on:blur={() => gradio.dispatch("blur")}
83
85
  on:focus={() => gradio.dispatch("focus")}
@@ -30,6 +30,7 @@ declare const __propDef: {
30
30
  min_width?: number | undefined;
31
31
  wrap_lines?: boolean | undefined;
32
32
  show_line_numbers?: boolean | undefined;
33
+ autocomplete?: boolean | undefined;
33
34
  interactive: boolean;
34
35
  };
35
36
  events: {
@@ -8,10 +8,13 @@ import {
8
8
  } from "@codemirror/view";
9
9
  import { StateEffect, EditorState } from "@codemirror/state";
10
10
  import { indentWithTab } from "@codemirror/commands";
11
+ import { autocompletion, acceptCompletion } from "@codemirror/autocomplete";
12
+ import { LanguageSupport } from "@codemirror/language";
11
13
  import { basicDark } from "cm6-theme-basic-dark";
12
14
  import { basicLight } from "cm6-theme-basic-light";
13
15
  import { basicSetup } from "./extensions";
14
16
  import { getLanguageExtension } from "./language";
17
+ import { create_pyodide_autocomplete } from "./autocomplete";
15
18
  export let class_names = "";
16
19
  export let value = "";
17
20
  export let dark_mode;
@@ -25,14 +28,21 @@ export let readonly = false;
25
28
  export let placeholder = void 0;
26
29
  export let wrap_lines = false;
27
30
  export let show_line_numbers = true;
31
+ export let autocomplete = false;
28
32
  const dispatch = createEventDispatcher();
29
33
  let lang_extension;
30
34
  let element;
31
35
  let view;
32
36
  $:
33
37
  get_lang(language);
38
+ const pyodide_autocomplete = create_pyodide_autocomplete();
34
39
  async function get_lang(val) {
35
40
  const ext = await getLanguageExtension(val);
41
+ if (pyodide_autocomplete && val === "python" && ext instanceof LanguageSupport) {
42
+ ext.support.push(
43
+ ext.language.data.of({ autocomplete: pyodide_autocomplete })
44
+ );
45
+ }
36
46
  lang_extension = ext;
37
47
  }
38
48
  $:
@@ -156,6 +166,18 @@ const FontTheme = EditorView.theme({
156
166
  borderLeftColor: "var(--body-text-color)"
157
167
  }
158
168
  });
169
+ const AutocompleteTheme = EditorView.theme({
170
+ ".cm-tooltip-autocomplete": {
171
+ "& > ul": {
172
+ backgroundColor: "var(--background-fill-primary)",
173
+ color: "var(--body-text-color)"
174
+ },
175
+ "& > ul > li[aria-selected]": {
176
+ backgroundColor: "var(--color-accent-soft)",
177
+ color: "var(--body-text-color)"
178
+ }
179
+ }
180
+ });
159
181
  function create_editor_state(_value) {
160
182
  return EditorState.create({
161
183
  doc: _value ?? void 0,
@@ -172,7 +194,9 @@ function get_base_extensions(basic2, use_tab2, placeholder2, readonly2, lang, sh
172
194
  extensions2.push(basicSetup);
173
195
  }
174
196
  if (use_tab2) {
175
- extensions2.push(keymap.of([indentWithTab]));
197
+ extensions2.push(
198
+ keymap.of([{ key: "Tab", run: acceptCompletion }, indentWithTab])
199
+ );
176
200
  }
177
201
  if (placeholder2) {
178
202
  extensions2.push(placeholderExt(placeholder2));
@@ -183,6 +207,10 @@ function get_base_extensions(basic2, use_tab2, placeholder2, readonly2, lang, sh
183
207
  if (show_line_numbers2) {
184
208
  extensions2.push(lineNumbers());
185
209
  }
210
+ if (autocomplete) {
211
+ extensions2.push(autocompletion());
212
+ extensions2.push(AutocompleteTheme);
213
+ }
186
214
  extensions2.push(EditorView.updateListener.of(handle_change));
187
215
  if (wrap_lines) {
188
216
  extensions2.push(EditorView.lineWrapping);
@@ -15,6 +15,7 @@ declare const __propDef: {
15
15
  placeholder?: string | HTMLElement | null | undefined;
16
16
  wrap_lines?: boolean | undefined;
17
17
  show_line_numbers?: boolean | undefined;
18
+ autocomplete?: boolean | undefined;
18
19
  };
19
20
  events: {
20
21
  change: CustomEvent<string>;
@@ -0,0 +1,4 @@
1
+ import type { CompletionContext, CompletionResult } from "@codemirror/autocomplete";
2
+ type CodeMirrorAutocompleteAsyncFn = (context: CompletionContext) => Promise<CompletionResult | null>;
3
+ export declare function create_pyodide_autocomplete(): CodeMirrorAutocompleteAsyncFn | null;
4
+ export {};
@@ -0,0 +1,49 @@
1
+ import { getWorkerProxyContext } from "@gradio/wasm/svelte";
2
+ // Jedi's completion types to CodeMirror's completion types.
3
+ // If not defined here, Jedi's completion types will be used.
4
+ const completion_type_map = {
5
+ module: "namespace"
6
+ };
7
+ export function create_pyodide_autocomplete() {
8
+ let maybe_worker_proxy;
9
+ try {
10
+ maybe_worker_proxy = getWorkerProxyContext();
11
+ }
12
+ catch (e) {
13
+ console.debug("Not in the Wasm env. Context-aware autocomplete disabled.");
14
+ return null;
15
+ }
16
+ if (!maybe_worker_proxy) {
17
+ return null;
18
+ }
19
+ const worker_proxy = maybe_worker_proxy;
20
+ return async function pyodide_autocomplete(context) {
21
+ try {
22
+ const completions = await worker_proxy.getCodeCompletions({
23
+ code: context.state.doc.toString(),
24
+ line: context.state.doc.lineAt(context.state.selection.main.head)
25
+ .number,
26
+ column: context.state.selection.main.head -
27
+ context.state.doc.lineAt(context.state.selection.main.head).from
28
+ });
29
+ if (completions.length === 0) {
30
+ return null;
31
+ }
32
+ return {
33
+ from: context.state.selection.main.head -
34
+ completions[0].completion_prefix_length,
35
+ options: completions.map((completion) => ({
36
+ label: completion.label,
37
+ type: completion_type_map[completion.type] ?? completion.type,
38
+ documentation: completion.docstring,
39
+ // Items starting with "_" are private attributes and should be sorted last.
40
+ boost: completion.label.startsWith("_") ? -1 : 0
41
+ }))
42
+ };
43
+ }
44
+ catch (e) {
45
+ console.error("Error getting completions", e);
46
+ return null;
47
+ }
48
+ };
49
+ }
@@ -1,23 +1,5 @@
1
1
  import { StreamLanguage } from "@codemirror/language";
2
- import { sql } from "@codemirror/legacy-modes/mode/sql";
3
2
  import { _ } from "svelte-i18n";
4
- const possible_langs = [
5
- "python",
6
- "c",
7
- "cpp",
8
- "markdown",
9
- "json",
10
- "html",
11
- "css",
12
- "javascript",
13
- "jinja2",
14
- "typescript",
15
- "yaml",
16
- "dockerfile",
17
- "shell",
18
- "r",
19
- "sql"
20
- ];
21
3
  const sql_dialects = [
22
4
  "standardSQL",
23
5
  "msSQL",
package/package.json CHANGED
@@ -1,38 +1,38 @@
1
1
  {
2
2
  "name": "@gradio/code",
3
- "version": "0.11.2",
3
+ "version": "0.13.0",
4
4
  "description": "Gradio UI packages",
5
5
  "type": "module",
6
6
  "author": "",
7
7
  "license": "ISC",
8
8
  "private": false,
9
9
  "dependencies": {
10
- "@codemirror/autocomplete": "^6.3.0",
11
- "@codemirror/commands": "^6.1.2",
12
- "@codemirror/lang-css": "^6.1.0",
13
- "@codemirror/lang-html": "^6.4.2",
14
- "@codemirror/lang-javascript": "^6.1.4",
10
+ "@codemirror/autocomplete": "^6.18.6",
11
+ "@codemirror/commands": "^6.8.0",
12
+ "@codemirror/lang-css": "^6.3.1",
13
+ "@codemirror/lang-html": "^6.4.9",
14
+ "@codemirror/lang-javascript": "^6.2.3",
15
15
  "@codemirror/lang-json": "^6.0.1",
16
- "@codemirror/lang-markdown": "^6.1.0",
17
- "@codemirror/lang-python": "^6.0.4",
18
- "@codemirror/language": "^6.6.0",
19
- "@codemirror/legacy-modes": "^6.3.1",
20
- "@codemirror/lint": "^6.0.0",
21
- "@codemirror/search": "^6.2.2",
22
- "@codemirror/state": "^6.1.2",
23
- "@codemirror/view": "^6.4.1",
24
- "@lezer/common": "^1.0.2",
25
- "@lezer/highlight": "^1.1.3",
26
- "@lezer/markdown": "^1.0.2",
16
+ "@codemirror/lang-markdown": "^6.3.2",
17
+ "@codemirror/lang-python": "^6.1.7",
18
+ "@codemirror/language": "^6.10.8",
19
+ "@codemirror/legacy-modes": "^6.4.3",
20
+ "@codemirror/lint": "^6.8.4",
21
+ "@codemirror/search": "^6.5.10",
22
+ "@codemirror/state": "^6.5.2",
23
+ "@codemirror/view": "^6.36.3",
24
+ "@lezer/common": "^1.2.3",
25
+ "@lezer/highlight": "^1.2.1",
26
+ "@lezer/markdown": "^1.4.2",
27
27
  "cm6-theme-basic-dark": "^0.2.0",
28
28
  "cm6-theme-basic-light": "^0.2.0",
29
29
  "codemirror": "^6.0.1",
30
- "@gradio/atoms": "^0.13.3",
30
+ "@gradio/atoms": "^0.14.1",
31
+ "@gradio/statustracker": "^0.10.6",
31
32
  "@gradio/icons": "^0.10.0",
32
- "@gradio/upload": "^0.15.4",
33
- "@gradio/statustracker": "^0.10.4",
34
33
  "@gradio/utils": "^0.10.1",
35
- "@gradio/wasm": "^0.17.4"
34
+ "@gradio/upload": "^0.15.6",
35
+ "@gradio/wasm": "^0.18.0"
36
36
  },
37
37
  "main_changeset": true,
38
38
  "main": "./Index.svelte",
@@ -9,11 +9,14 @@
9
9
  } from "@codemirror/view";
10
10
  import { StateEffect, EditorState, type Extension } from "@codemirror/state";
11
11
  import { indentWithTab } from "@codemirror/commands";
12
+ import { autocompletion, acceptCompletion } from "@codemirror/autocomplete";
13
+ import { LanguageSupport } from "@codemirror/language";
12
14
 
13
15
  import { basicDark } from "cm6-theme-basic-dark";
14
16
  import { basicLight } from "cm6-theme-basic-light";
15
17
  import { basicSetup } from "./extensions";
16
18
  import { getLanguageExtension } from "./language";
19
+ import { create_pyodide_autocomplete } from "./autocomplete";
17
20
 
18
21
  export let class_names = "";
19
22
  export let value = "";
@@ -28,6 +31,7 @@
28
31
  export let placeholder: string | HTMLElement | null | undefined = undefined;
29
32
  export let wrap_lines = false;
30
33
  export let show_line_numbers = true;
34
+ export let autocomplete = false;
31
35
 
32
36
  const dispatch = createEventDispatcher<{
33
37
  change: string;
@@ -40,8 +44,19 @@
40
44
 
41
45
  $: get_lang(language);
42
46
 
47
+ const pyodide_autocomplete = create_pyodide_autocomplete();
48
+
43
49
  async function get_lang(val: string): Promise<void> {
44
50
  const ext = await getLanguageExtension(val);
51
+ if (
52
+ pyodide_autocomplete &&
53
+ val === "python" &&
54
+ ext instanceof LanguageSupport
55
+ ) {
56
+ (ext.support as Extension[]).push(
57
+ ext.language.data.of({ autocomplete: pyodide_autocomplete })
58
+ );
59
+ }
45
60
  lang_extension = ext;
46
61
  }
47
62
 
@@ -175,6 +190,19 @@
175
190
  }
176
191
  });
177
192
 
193
+ const AutocompleteTheme = EditorView.theme({
194
+ ".cm-tooltip-autocomplete": {
195
+ "& > ul": {
196
+ backgroundColor: "var(--background-fill-primary)",
197
+ color: "var(--body-text-color)"
198
+ },
199
+ "& > ul > li[aria-selected]": {
200
+ backgroundColor: "var(--color-accent-soft)",
201
+ color: "var(--body-text-color)"
202
+ }
203
+ }
204
+ });
205
+
178
206
  function create_editor_state(_value: string | null | undefined): EditorState {
179
207
  return EditorState.create({
180
208
  doc: _value ?? undefined,
@@ -200,7 +228,9 @@
200
228
  extensions.push(basicSetup);
201
229
  }
202
230
  if (use_tab) {
203
- extensions.push(keymap.of([indentWithTab]));
231
+ extensions.push(
232
+ keymap.of([{ key: "Tab", run: acceptCompletion }, indentWithTab])
233
+ );
204
234
  }
205
235
  if (placeholder) {
206
236
  extensions.push(placeholderExt(placeholder));
@@ -208,10 +238,13 @@
208
238
  if (lang) {
209
239
  extensions.push(lang);
210
240
  }
211
-
212
241
  if (show_line_numbers) {
213
242
  extensions.push(lineNumbers());
214
243
  }
244
+ if (autocomplete) {
245
+ extensions.push(autocompletion());
246
+ extensions.push(AutocompleteTheme);
247
+ }
215
248
 
216
249
  extensions.push(EditorView.updateListener.of(handle_change));
217
250
  if (wrap_lines) {
@@ -0,0 +1,63 @@
1
+ import type {
2
+ CompletionContext,
3
+ CompletionResult
4
+ } from "@codemirror/autocomplete";
5
+ import { getWorkerProxyContext } from "@gradio/wasm/svelte";
6
+ import type { WorkerProxy } from "@gradio/wasm";
7
+
8
+ // Jedi's completion types to CodeMirror's completion types.
9
+ // If not defined here, Jedi's completion types will be used.
10
+ const completion_type_map: Record<string, string> = {
11
+ module: "namespace"
12
+ };
13
+
14
+ type CodeMirrorAutocompleteAsyncFn = (
15
+ context: CompletionContext
16
+ ) => Promise<CompletionResult | null>;
17
+
18
+ export function create_pyodide_autocomplete(): CodeMirrorAutocompleteAsyncFn | null {
19
+ let maybe_worker_proxy: WorkerProxy | undefined;
20
+ try {
21
+ maybe_worker_proxy = getWorkerProxyContext();
22
+ } catch (e) {
23
+ console.debug("Not in the Wasm env. Context-aware autocomplete disabled.");
24
+ return null;
25
+ }
26
+ if (!maybe_worker_proxy) {
27
+ return null;
28
+ }
29
+ const worker_proxy = maybe_worker_proxy;
30
+
31
+ return async function pyodide_autocomplete(
32
+ context: CompletionContext
33
+ ): Promise<CompletionResult | null> {
34
+ try {
35
+ const completions = await worker_proxy.getCodeCompletions({
36
+ code: context.state.doc.toString(),
37
+ line: context.state.doc.lineAt(context.state.selection.main.head)
38
+ .number,
39
+ column:
40
+ context.state.selection.main.head -
41
+ context.state.doc.lineAt(context.state.selection.main.head).from
42
+ });
43
+ if (completions.length === 0) {
44
+ return null;
45
+ }
46
+ return {
47
+ from:
48
+ context.state.selection.main.head -
49
+ completions[0].completion_prefix_length,
50
+ options: completions.map((completion) => ({
51
+ label: completion.label,
52
+ type: completion_type_map[completion.type] ?? completion.type,
53
+ documentation: completion.docstring,
54
+ // Items starting with "_" are private attributes and should be sorted last.
55
+ boost: completion.label.startsWith("_") ? -1 : 0
56
+ }))
57
+ };
58
+ } catch (e) {
59
+ console.error("Error getting completions", e);
60
+ return null;
61
+ }
62
+ };
63
+ }
@@ -1,26 +1,7 @@
1
1
  import type { Extension } from "@codemirror/state";
2
2
  import { StreamLanguage } from "@codemirror/language";
3
- import { sql } from "@codemirror/legacy-modes/mode/sql";
4
3
  import { _ } from "svelte-i18n";
5
4
 
6
- const possible_langs = [
7
- "python",
8
- "c",
9
- "cpp",
10
- "markdown",
11
- "json",
12
- "html",
13
- "css",
14
- "javascript",
15
- "jinja2",
16
- "typescript",
17
- "yaml",
18
- "dockerfile",
19
- "shell",
20
- "r",
21
- "sql"
22
- ];
23
-
24
5
  const sql_dialects = [
25
6
  "standardSQL",
26
7
  "msSQL",