akhaliq HF Staff commited on
Commit
772c871
·
verified ·
1 Parent(s): 33fee17

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +209 -93
app.py CHANGED
@@ -1,204 +1,320 @@
1
  import gradio as gr
2
- import json
3
  import time
4
 
5
- # Simulated file storage (in-memory dictionary for demo)
6
- files = {"untitled.py": ""}
 
7
 
8
  # Load file content into editor
9
- def load_file(file, current_file):
10
  global files
11
  if file is not None:
12
  with open(file.name, "r") as f:
13
  code = f.read()
14
  filename = file.name.split("/")[-1]
15
  files[filename] = code
16
- return code, filename, list(files.keys()), code
17
- return files.get(current_file, ""), current_file, list(files.keys()), files.get(current_file, "")
 
 
18
 
19
  # Save current file content
20
  def save_file(code, current_file):
21
  global files
22
  files[current_file] = code
23
- return list(files.keys()), f"Saved {current_file}"
24
 
25
- # Simulate running code with terminal history
26
  def run_code(code, terminal_history):
27
  timestamp = time.strftime("%H:%M:%S")
28
  output = f"[{timestamp}] Ran:\n{code}\nOutput: Simulated execution successful"
29
  return f"{terminal_history}\n{output}".strip()
30
 
31
- # AI-powered suggestions (expandable with real model)
 
 
 
 
 
 
 
 
 
 
32
  def get_suggestions(code):
33
- if "def" in code.lower():
 
34
  return ["def function_name():", "def main():", "def __init__(self):"]
35
- elif "print" in code.lower():
36
  return ["print('Hello, World!')", "print(variable)", "print(f'String: {var}')"]
37
- elif "import" in code.lower():
38
  return ["import os", "import sys", "import numpy as np"]
39
  return ["# Start typing for suggestions"]
40
 
41
- # Insert suggestion into editor
42
  def insert_suggestion(code, suggestion):
43
  if suggestion:
44
  lines = code.split("\n")
45
  last_line = lines[-1]
46
- if last_line.strip():
47
- return code + "\n" + suggestion
48
- return code + suggestion
49
  return code
50
 
51
- # Switch tabs (load different file)
52
- def switch_tab(selected_file):
53
- global files
54
- return files.get(selected_file, ""), selected_file, list(files.keys())
55
 
56
  # Add new file
57
- def add_new_file():
58
- global files
59
  new_file = f"untitled_{len(files)}.py"
60
  files[new_file] = ""
61
- return "", new_file, list(files.keys())
 
62
 
63
- # Download current file
 
 
 
 
 
 
 
 
64
  def download_code(code, current_file):
65
  return code, current_file
66
 
67
- # Gradio interface with VS Code-like complexity
 
 
 
 
 
 
 
 
 
 
 
68
  with gr.Blocks(
69
  title="VS Code Clone",
70
  css="""
71
- .gradio-container { background-color: #1e1e1e; color: #d4d4d4; font-family: 'Consolas', monospace; height: 100vh; }
72
- .topbar { background-color: #333333; padding: 5px; border-bottom: 1px solid #3c3c3c; }
73
- .sidebar { background-color: #252526; padding: 10px; border-right: 1px solid #3c3c3c; }
74
- .editor { background-color: #252526; border: 1px solid #3c3c3c; }
75
  .terminal { background-color: #0e0e0e; color: #b5cea8; font-size: 12px; }
76
- .suggestions { background-color: #252526; border: 1px solid #3c3c3c; }
77
- button { background-color: #007acc; color: white; border: none; padding: 5px 10px; margin: 2px; }
78
- button:hover { background-color: #005f99; }
79
  .tabs { display: flex; gap: 5px; background-color: #1e1e1e; padding: 5px; border-bottom: 1px solid #3c3c3c; }
80
  .tab { background-color: #2d2d2d; padding: 5px 10px; cursor: pointer; }
81
  .tab.active { background-color: #007acc; }
82
- .file-list { max-height: 200px; overflow-y: auto; }
83
- """,
84
- theme="dark"
 
 
 
 
 
 
 
 
 
 
85
  ) as app:
86
  # States
87
  current_file = gr.State(value="untitled.py")
88
  terminal_history = gr.State(value="")
 
 
89
 
90
- # Top bar with controls
91
- with gr.Row(elem_classes="topbar"):
92
- run_button = gr.Button("▶ Run")
93
- save_button = gr.Button("💾 Save")
94
- new_file_button = gr.Button("➕ New File")
95
- gr.Markdown(f"### VS Code Clone - {time.strftime('%Y-%m-%d')}", elem_classes="topbar")
96
-
97
- # Tabbed editor
98
- with gr.Row(elem_classes="tabs"):
99
- file_tabs = gr.Dropdown(label="Open Files", choices=list(files.keys()), value="untitled.py", interactive=True)
100
-
101
- # Main layout
102
  with gr.Row():
 
 
 
 
 
103
  # Sidebar (File Explorer)
104
- with gr.Column(scale=1, elem_classes="sidebar"):
105
  gr.Markdown("### Explorer")
106
  file_upload = gr.File(label="Upload File")
107
  file_list = gr.Listbox(label="Files", choices=list(files.keys()), interactive=True, elem_classes="file-list")
108
- status_display = gr.Textbox(label="Status", interactive=False)
109
 
110
- # Editor and Terminal/Suggestions
111
  with gr.Column(scale=4):
112
- code_editor = gr.Code(
113
- label="Editor",
114
- language="python",
115
- lines=20,
116
- elem_classes="editor"
117
- )
118
  with gr.Row():
119
- terminal_output = gr.Textbox(label="Terminal", lines=10, elem_classes="terminal")
120
- suggestions_list = gr.Listbox(label="Suggestions", choices=[], interactive=True, elem_classes="suggestions")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
 
122
- # Hidden download output
123
  download_output = gr.File(label="Download", visible=False)
124
 
125
- # JavaScript for keyboard shortcuts (Ctrl+S to save, Ctrl+R to run)
126
  app.load(_js="""
127
  () => {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
  document.addEventListener('keydown', (e) => {
 
 
 
 
 
129
  if (e.ctrlKey && e.key === 's') {
130
  e.preventDefault();
131
- document.querySelectorAll('button')[1].click(); // Save button
132
  }
133
  if (e.ctrlKey && e.key === 'r') {
134
  e.preventDefault();
135
- document.querySelectorAll('button')[0].click(); // Run button
136
  }
137
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
  }
139
- """)
 
 
 
 
140
 
141
- # Event handlers
142
- # File upload
143
  file_upload.change(
144
- fn=load_file,
145
- inputs=[file_upload, current_file],
146
- outputs=[code_editor, current_file, file_list, code_editor]
147
  )
148
 
149
- # Save file
150
- save_button.click(
151
- fn=save_file,
152
  inputs=[code_editor, current_file],
153
- outputs=[file_list, status_display]
154
  ).then(
155
- fn=download_code,
156
  inputs=[code_editor, current_file],
157
  outputs=[download_output]
158
  )
159
 
160
- # Run code
161
- run_button.click(
162
- fn=run_code,
163
  inputs=[code_editor, terminal_history],
164
  outputs=[terminal_output]
165
  ).then(
166
- fn=lambda x: x,
 
 
 
 
 
 
 
 
 
 
167
  inputs=[terminal_output],
168
  outputs=[terminal_history]
169
  )
170
 
171
- # Suggestions
172
  code_editor.change(
173
- fn=get_suggestions,
174
  inputs=[code_editor],
175
  outputs=[suggestions_list]
176
  )
 
177
  suggestions_list.select(
178
- fn=insert_suggestion,
179
  inputs=[code_editor, suggestions_list],
180
  outputs=[code_editor]
181
  )
182
 
183
- # Tab switching
184
  file_tabs.change(
185
- fn=switch_tab,
186
- inputs=[file_tabs],
187
- outputs=[code_editor, current_file, file_list]
 
 
 
 
 
 
188
  )
189
 
190
- # New file
191
- new_file_button.click(
192
- fn=add_new_file,
193
- outputs=[code_editor, current_file, file_list]
 
 
 
 
194
  )
195
 
196
- # File list selection
197
  file_list.select(
198
- fn=switch_tab,
199
- inputs=[file_list],
200
- outputs=[code_editor, current_file, file_list]
 
 
 
 
201
  )
202
 
203
- # Launch the app
 
 
 
 
 
 
204
  app.launch()
 
1
  import gradio as gr
 
2
  import time
3
 
4
+ # Simulated file storage (in-memory dictionary)
5
+ files = {"untitled.py": ""} # file_name: content
6
+ open_files = ["untitled.py"] # List of open files
7
 
8
  # Load file content into editor
9
+ def load_file(file, current_file, open_files):
10
  global files
11
  if file is not None:
12
  with open(file.name, "r") as f:
13
  code = f.read()
14
  filename = file.name.split("/")[-1]
15
  files[filename] = code
16
+ if filename not in open_files:
17
+ open_files.append(filename)
18
+ return code, filename, list(files.keys()), open_files, code
19
+ return files.get(current_file, ""), current_file, list(files.keys()), open_files, files.get(current_file, "")
20
 
21
  # Save current file content
22
  def save_file(code, current_file):
23
  global files
24
  files[current_file] = code
25
+ return f"Saved {current_file}"
26
 
27
+ # Simulate running code
28
  def run_code(code, terminal_history):
29
  timestamp = time.strftime("%H:%M:%S")
30
  output = f"[{timestamp}] Ran:\n{code}\nOutput: Simulated execution successful"
31
  return f"{terminal_history}\n{output}".strip()
32
 
33
+ # Process terminal commands
34
+ def process_command(cmd, files, history):
35
+ if cmd.strip() == "ls":
36
+ output = "\n".join(files.keys())
37
+ elif cmd.startswith("echo "):
38
+ output = cmd[5:]
39
+ else:
40
+ output = f"Command not recognized: {cmd}"
41
+ return f"{history}\n$ {cmd}\n{output}"
42
+
43
+ # AI-powered suggestions
44
  def get_suggestions(code):
45
+ code = code.lower()
46
+ if "def" in code:
47
  return ["def function_name():", "def main():", "def __init__(self):"]
48
+ elif "print" in code:
49
  return ["print('Hello, World!')", "print(variable)", "print(f'String: {var}')"]
50
+ elif "import" in code:
51
  return ["import os", "import sys", "import numpy as np"]
52
  return ["# Start typing for suggestions"]
53
 
54
+ # Insert suggestion
55
  def insert_suggestion(code, suggestion):
56
  if suggestion:
57
  lines = code.split("\n")
58
  last_line = lines[-1]
59
+ return code + ("\n" + suggestion if last_line.strip() else suggestion)
 
 
60
  return code
61
 
62
+ # Switch tabs
63
+ def switch_tab(selected, files):
64
+ return files.get(selected, ""), selected
 
65
 
66
  # Add new file
67
+ def add_new_file(open_files, files):
 
68
  new_file = f"untitled_{len(files)}.py"
69
  files[new_file] = ""
70
+ open_files.append(new_file)
71
+ return "", new_file, list(files.keys()), open_files, files[new_file]
72
 
73
+ # Close tab
74
+ def close_tab(open_files, current_file, files):
75
+ if len(open_files) > 1:
76
+ new_open_files = [f for f in open_files if f != current_file]
77
+ new_current = new_open_files[0]
78
+ return new_open_files, new_current, files[new_current]
79
+ return open_files, current_file, files[current_file]
80
+
81
+ # Download file
82
  def download_code(code, current_file):
83
  return code, current_file
84
 
85
+ # Process command palette
86
+ def process_palette(cmd, theme, files, current_file):
87
+ if cmd == "theme dark":
88
+ return "dark", "Theme set to dark"
89
+ elif cmd == "theme light":
90
+ return "light", "Theme set to light"
91
+ elif cmd == "save":
92
+ files[current_file] = code_editor.value
93
+ return theme, f"Saved {current_file}"
94
+ return theme, f"Command not found: {cmd}"
95
+
96
+ # Gradio interface
97
  with gr.Blocks(
98
  title="VS Code Clone",
99
  css="""
100
+ .gradio-container { background-color: #1e1e1e; color: #d4d4d4; font-family: 'Consolas', monospace; height: 100vh; margin: 0; }
101
+ .activity-bar { background-color: #333; padding: 10px; width: 50px; min-width: 50px; }
102
+ .sidebar { background-color: #252526; padding: 10px; width: 200px; min-width: 200px; }
103
+ .editor { background-color: #1e1e1e; border: none; }
104
  .terminal { background-color: #0e0e0e; color: #b5cea8; font-size: 12px; }
105
+ .status-bar { background-color: #007acc; color: white; padding: 5px; }
 
 
106
  .tabs { display: flex; gap: 5px; background-color: #1e1e1e; padding: 5px; border-bottom: 1px solid #3c3c3c; }
107
  .tab { background-color: #2d2d2d; padding: 5px 10px; cursor: pointer; }
108
  .tab.active { background-color: #007acc; }
109
+ button { background-color: #007acc; color: white; border: none; padding: 5px; margin: 2px; }
110
+ button:hover { background-color: #005f99; }
111
+ .file-list { max-height: 300px; overflow-y: auto; }
112
+ .command-palette { position: absolute; top: 20%; left: 30%; width: 40%; background: #252526; z-index: 1000; padding: 10px; }
113
+ .light .gradio-container { background-color: #ffffff; color: #000000; }
114
+ .light .editor { background-color: #ffffff; color: #000000; }
115
+ .light .sidebar { background-color: #f3f3f3; }
116
+ .light .terminal { background-color: #f0f0f0; color: #000000; }
117
+ .light .status-bar { background-color: #0066cc; }
118
+ .light .tabs { background-color: #ffffff; }
119
+ .light .tab { background-color: #e0e0e0; }
120
+ .light .tab.active { background-color: #0066cc; }
121
+ """
122
  ) as app:
123
  # States
124
  current_file = gr.State(value="untitled.py")
125
  terminal_history = gr.State(value="")
126
+ theme_state = gr.State(value="dark")
127
+ cursor_position = gr.State(value="Ln 1, Col 1")
128
 
129
+ # Layout
 
 
 
 
 
 
 
 
 
 
 
130
  with gr.Row():
131
+ # Activity Bar
132
+ with gr.Column(scale=0, elem_classes="activity-bar"):
133
+ explorer_btn = gr.Button("📁")
134
+ terminal_btn = gr.Button("🖥️")
135
+
136
  # Sidebar (File Explorer)
137
+ with gr.Column(scale=1, visible=False, elem_classes="sidebar") as sidebar:
138
  gr.Markdown("### Explorer")
139
  file_upload = gr.File(label="Upload File")
140
  file_list = gr.Listbox(label="Files", choices=list(files.keys()), interactive=True, elem_classes="file-list")
 
141
 
142
+ # Editor Pane
143
  with gr.Column(scale=4):
144
+ with gr.Row(elem_classes="tabs"):
145
+ file_tabs = gr.Dropdown(label="Open Files", choices=open_files, value="untitled.py", interactive=True)
146
+ new_file_btn = gr.Button("")
147
+ close_tab_btn = gr.Button("❌")
148
+ code_editor = gr.Code(label="Editor", language="python", lines=20, elem_classes="editor")
 
149
  with gr.Row():
150
+ with gr.Column(scale=3):
151
+ terminal_panel = gr.Column(visible=False, elem_classes="terminal")
152
+ with terminal_panel:
153
+ terminal_output = gr.Textbox(label="Terminal", lines=10, interactive=False)
154
+ terminal_input = gr.Textbox(label=">", placeholder="Type command and press Enter")
155
+ with gr.Column(scale=1):
156
+ suggestions_list = gr.Listbox(label="Suggestions", choices=[], interactive=True)
157
+
158
+ # Status Bar
159
+ with gr.Row(elem_classes="status-bar"):
160
+ run_btn = gr.Button("▶ Run")
161
+ save_btn = gr.Button("💾 Save")
162
+ status_info = gr.Textbox(value="Python • Ln 1, Col 1", interactive=False)
163
+
164
+ # Command Palette
165
+ command_palette = gr.Textbox(label="> Command Palette", visible=False, elem_classes="command-palette")
166
 
167
+ # Hidden Download Output
168
  download_output = gr.File(label="Download", visible=False)
169
 
170
+ # JavaScript for shortcuts and cursor tracking
171
  app.load(_js="""
172
  () => {
173
+ const editor = document.querySelector('#code_editor textarea');
174
+ const status = document.querySelector('#status_info input');
175
+ const palette = document.querySelector('#command_palette');
176
+ const themeInput = document.querySelector('#theme_state input');
177
+ const container = document.querySelector('.gradio-container');
178
+
179
+ // Cursor position
180
+ function getCursorPosition(textarea) {
181
+ const text = textarea.value;
182
+ const pos = textarea.selectionStart;
183
+ const lines = text.substr(0, pos).split('\\n');
184
+ return `Python • Ln ${lines.length}, Col ${lines[lines.length - 1].length + 1}`;
185
+ }
186
+ editor.addEventListener('keyup', () => {
187
+ status.value = getCursorPosition(editor);
188
+ status.dispatchEvent(new Event('input'));
189
+ });
190
+ editor.addEventListener('click', () => {
191
+ status.value = getCursorPosition(editor);
192
+ status.dispatchEvent(new Event('input'));
193
+ });
194
+
195
+ // Shortcuts
196
  document.addEventListener('keydown', (e) => {
197
+ if (e.ctrlKey && e.shiftKey && e.key === 'P') {
198
+ e.preventDefault();
199
+ palette.style.display = 'block';
200
+ palette.querySelector('input').focus();
201
+ }
202
  if (e.ctrlKey && e.key === 's') {
203
  e.preventDefault();
204
+ document.querySelector('#save_btn').click();
205
  }
206
  if (e.ctrlKey && e.key === 'r') {
207
  e.preventDefault();
208
+ document.querySelector('#run_btn').click();
209
  }
210
  });
211
+
212
+ // Hide palette on Escape
213
+ palette.querySelector('input').addEventListener('keydown', (e) => {
214
+ if (e.key === 'Escape') {
215
+ palette.style.display = 'none';
216
+ }
217
+ });
218
+
219
+ // Theme switching
220
+ container.classList.add(themeInput.value);
221
+ const observer = new MutationObserver(() => {
222
+ container.classList.remove('light', 'dark');
223
+ container.classList.add(themeInput.value);
224
+ });
225
+ observer.observe(themeInput, {attributes: true});
226
  }
227
+ """, outputs=[status_info])
228
+
229
+ # Event Handlers
230
+ explorer_btn.click(lambda v: gr.update(visible=not v), inputs=[sidebar.visible], outputs=[sidebar])
231
+ terminal_btn.click(lambda v: gr.update(visible=not v), inputs=[terminal_panel.visible], outputs=[terminal_panel])
232
 
 
 
233
  file_upload.change(
234
+ load_file,
235
+ inputs=[file_upload, current_file, file_tabs.choices],
236
+ outputs=[code_editor, current_file, file_list, file_tabs, code_editor]
237
  )
238
 
239
+ save_btn.click(
240
+ save_file,
 
241
  inputs=[code_editor, current_file],
242
+ outputs=[status_info]
243
  ).then(
244
+ download_code,
245
  inputs=[code_editor, current_file],
246
  outputs=[download_output]
247
  )
248
 
249
+ run_btn.click(
250
+ run_code,
 
251
  inputs=[code_editor, terminal_history],
252
  outputs=[terminal_output]
253
  ).then(
254
+ lambda x: x,
255
+ inputs=[terminal_output],
256
+ outputs=[terminal_history]
257
+ )
258
+
259
+ terminal_input.submit(
260
+ process_command,
261
+ inputs=[terminal_input, files, terminal_history],
262
+ outputs=[terminal_output]
263
+ ).then(lambda: "", outputs=[terminal_input]).then(
264
+ lambda x: x,
265
  inputs=[terminal_output],
266
  outputs=[terminal_history]
267
  )
268
 
 
269
  code_editor.change(
270
+ get_suggestions,
271
  inputs=[code_editor],
272
  outputs=[suggestions_list]
273
  )
274
+
275
  suggestions_list.select(
276
+ insert_suggestion,
277
  inputs=[code_editor, suggestions_list],
278
  outputs=[code_editor]
279
  )
280
 
 
281
  file_tabs.change(
282
+ switch_tab,
283
+ inputs=[file_tabs, files],
284
+ outputs=[code_editor, current_file]
285
+ )
286
+
287
+ new_file_btn.click(
288
+ add_new_file,
289
+ inputs=[file_tabs.choices, files],
290
+ outputs=[code_editor, current_file, file_list, file_tabs, code_editor]
291
  )
292
 
293
+ close_tab_btn.click(
294
+ close_tab,
295
+ inputs=[file_tabs.choices, current_file, files],
296
+ outputs=[file_tabs.choices, current_file, code_editor]
297
+ ).then(
298
+ lambda open_files, current_file: gr.update(choices=open_files, value=current_file),
299
+ inputs=[file_tabs.choices, current_file],
300
+ outputs=[file_tabs]
301
  )
302
 
 
303
  file_list.select(
304
+ lambda selected, open_files, files: (files[selected], selected, open_files + [selected] if selected not in open_files else open_files),
305
+ inputs=[file_list, file_tabs.choices, files],
306
+ outputs=[code_editor, current_file, file_tabs.choices]
307
+ ).then(
308
+ lambda open_files, current_file: gr.update(choices=open_files, value=current_file),
309
+ inputs=[file_tabs.choices, current_file],
310
+ outputs=[file_tabs]
311
  )
312
 
313
+ command_palette.submit(
314
+ process_palette,
315
+ inputs=[command_palette, theme_state, files, current_file],
316
+ outputs=[theme_state, status_info]
317
+ ).then(lambda: gr.update(visible=False), outputs=[command_palette])
318
+
319
+ # Launch
320
  app.launch()