euporie 2.8.5__py3-none-any.whl → 2.8.7__py3-none-any.whl

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.
Files changed (74) hide show
  1. euporie/console/app.py +2 -0
  2. euporie/console/tabs/console.py +27 -17
  3. euporie/core/__init__.py +2 -2
  4. euporie/core/__main__.py +2 -2
  5. euporie/core/_settings.py +7 -2
  6. euporie/core/app/_commands.py +20 -12
  7. euporie/core/app/_settings.py +34 -4
  8. euporie/core/app/app.py +31 -18
  9. euporie/core/bars/command.py +53 -27
  10. euporie/core/bars/search.py +43 -2
  11. euporie/core/border.py +7 -2
  12. euporie/core/comm/base.py +2 -2
  13. euporie/core/comm/ipywidgets.py +3 -3
  14. euporie/core/commands.py +44 -24
  15. euporie/core/completion.py +14 -6
  16. euporie/core/convert/datum.py +7 -7
  17. euporie/core/data_structures.py +20 -1
  18. euporie/core/filters.py +40 -9
  19. euporie/core/format.py +2 -3
  20. euporie/core/ft/html.py +47 -40
  21. euporie/core/graphics.py +199 -31
  22. euporie/core/history.py +15 -5
  23. euporie/core/inspection.py +16 -9
  24. euporie/core/kernel/__init__.py +53 -1
  25. euporie/core/kernel/base.py +571 -0
  26. euporie/core/kernel/{client.py → jupyter.py} +173 -430
  27. euporie/core/kernel/{manager.py → jupyter_manager.py} +4 -3
  28. euporie/core/kernel/local.py +694 -0
  29. euporie/core/key_binding/bindings/basic.py +6 -3
  30. euporie/core/keys.py +26 -25
  31. euporie/core/layout/cache.py +31 -7
  32. euporie/core/layout/containers.py +88 -13
  33. euporie/core/layout/scroll.py +69 -170
  34. euporie/core/log.py +2 -5
  35. euporie/core/path.py +61 -13
  36. euporie/core/style.py +2 -1
  37. euporie/core/suggest.py +155 -74
  38. euporie/core/tabs/__init__.py +12 -4
  39. euporie/core/tabs/_commands.py +76 -0
  40. euporie/core/tabs/_settings.py +16 -0
  41. euporie/core/tabs/base.py +89 -9
  42. euporie/core/tabs/kernel.py +83 -38
  43. euporie/core/tabs/notebook.py +28 -76
  44. euporie/core/utils.py +2 -19
  45. euporie/core/validation.py +8 -8
  46. euporie/core/widgets/_settings.py +19 -2
  47. euporie/core/widgets/cell.py +32 -32
  48. euporie/core/widgets/cell_outputs.py +10 -1
  49. euporie/core/widgets/dialog.py +60 -76
  50. euporie/core/widgets/display.py +2 -2
  51. euporie/core/widgets/forms.py +71 -59
  52. euporie/core/widgets/inputs.py +7 -4
  53. euporie/core/widgets/layout.py +281 -93
  54. euporie/core/widgets/menu.py +56 -16
  55. euporie/core/widgets/palette.py +3 -1
  56. euporie/core/widgets/tree.py +86 -76
  57. euporie/notebook/app.py +35 -16
  58. euporie/notebook/tabs/display.py +2 -2
  59. euporie/notebook/tabs/edit.py +11 -46
  60. euporie/notebook/tabs/json.py +8 -4
  61. euporie/notebook/tabs/notebook.py +26 -8
  62. euporie/preview/tabs/notebook.py +17 -13
  63. euporie/web/__init__.py +1 -0
  64. euporie/web/tabs/__init__.py +14 -0
  65. euporie/web/tabs/web.py +30 -5
  66. euporie/web/widgets/__init__.py +1 -0
  67. euporie/web/widgets/webview.py +5 -4
  68. {euporie-2.8.5.dist-info → euporie-2.8.7.dist-info}/METADATA +4 -2
  69. {euporie-2.8.5.dist-info → euporie-2.8.7.dist-info}/RECORD +74 -68
  70. {euporie-2.8.5.dist-info → euporie-2.8.7.dist-info}/entry_points.txt +1 -1
  71. {euporie-2.8.5.dist-info → euporie-2.8.7.dist-info}/licenses/LICENSE +1 -1
  72. {euporie-2.8.5.data → euporie-2.8.7.data}/data/share/applications/euporie-console.desktop +0 -0
  73. {euporie-2.8.5.data → euporie-2.8.7.data}/data/share/applications/euporie-notebook.desktop +0 -0
  74. {euporie-2.8.5.dist-info → euporie-2.8.7.dist-info}/WHEEL +0 -0
@@ -116,6 +116,16 @@ class CellOutputDataElement(CellOutputElement):
116
116
  format_ = data_format
117
117
  break
118
118
 
119
+ config = get_app().config
120
+
121
+ # Limit size of text only outputs
122
+ if (
123
+ format_ == "ansi"
124
+ and (limit := config.text_output_limit) > 0
125
+ and len(data) > limit
126
+ ):
127
+ data = data[:limit] + "\n… (Output truncated)"
128
+
119
129
  self._datum = Datum(
120
130
  data,
121
131
  format_,
@@ -123,7 +133,6 @@ class CellOutputDataElement(CellOutputElement):
123
133
  py=metadata.get("height"),
124
134
  bg=bg_color,
125
135
  )
126
- config = get_app().config
127
136
 
128
137
  self.container = Display(
129
138
  self._datum,
@@ -16,6 +16,7 @@ from prompt_toolkit.filters import (
16
16
  buffer_has_focus,
17
17
  has_completions,
18
18
  has_focus,
19
+ vi_insert_mode,
19
20
  )
20
21
  from prompt_toolkit.formatted_text import AnyFormattedText, to_formatted_text
21
22
  from prompt_toolkit.formatted_text.utils import split_lines
@@ -40,7 +41,6 @@ from euporie.core.border import (
40
41
  UpperRightHalfLine,
41
42
  )
42
43
  from euporie.core.commands import add_cmd
43
- from euporie.core.filters import tab_has_focus
44
44
  from euporie.core.ft.utils import FormattedTextAlign, align, lex
45
45
  from euporie.core.key_binding.registry import register_bindings
46
46
  from euporie.core.layout.containers import HSplit, VSplit, Window
@@ -64,6 +64,7 @@ if TYPE_CHECKING:
64
64
  from prompt_toolkit.mouse_events import MouseEvent
65
65
 
66
66
  from euporie.core.app.app import BaseApp
67
+ from euporie.core.kernel.base import KernelInfo
67
68
  from euporie.core.tabs.base import Tab
68
69
  from euporie.core.tabs.kernel import KernelTab
69
70
 
@@ -197,7 +198,7 @@ class Dialog(Float, metaclass=ABCMeta):
197
198
 
198
199
  # Create key-bindings
199
200
  kb = KeyBindings()
200
- kb.add("escape")(lambda event: self.hide())
201
+ kb.add("escape", filter=~(buffer_has_focus & vi_insert_mode))(self.hide)
201
202
  kb.add("tab", filter=~has_completions)(focus_next)
202
203
  kb.add("s-tab", filter=~has_completions)(focus_previous)
203
204
 
@@ -597,21 +598,6 @@ class SaveAsDialog(FileDialog):
597
598
  if callable(cb):
598
599
  cb()
599
600
 
600
- # ################################### Commands ####################################
601
-
602
- @staticmethod
603
- @add_cmd(
604
- menu_title="Save As…",
605
- filter=tab_has_focus,
606
- )
607
- def _save_as() -> None:
608
- """Save the current file at a new location."""
609
- from euporie.core.app.current import get_app
610
-
611
- app = get_app()
612
- if dialog := app.dialogs.get("save-as"):
613
- dialog.show(tab=app.tab)
614
-
615
601
  # ################################# Key Bindings ##################################
616
602
 
617
603
  register_bindings(
@@ -655,62 +641,37 @@ class SelectKernelDialog(Dialog):
655
641
 
656
642
  title = "Select Kernel"
657
643
 
658
- def load(
659
- self,
660
- kernel_specs: dict[str, Any] | None = None,
661
- runtime_dirs: dict[str, Path] | None = None,
662
- tab: KernelTab | None = None,
663
- message: str = "",
664
- ) -> None:
644
+ def load(self, tab: KernelTab | None = None, message: str = "") -> None:
665
645
  """Load dialog body & buttons."""
666
- from jupyter_core.paths import jupyter_runtime_dir
667
-
646
+ from euporie.core.kernel import list_kernels
668
647
  from euporie.core.widgets.layout import TabbedSplit
669
648
 
670
- kernel_specs = kernel_specs or {}
671
- runtime_dirs = runtime_dirs or {}
672
-
673
- options_specs = Select(
674
- options=list(kernel_specs.keys()),
675
- labels=[
676
- kernel_spec.get("spec", {}).get("display_name", kernel_name)
677
- for kernel_name, kernel_spec in kernel_specs.items()
678
- ],
679
- style="class:input,radio-buttons",
680
- prefix=("○", "◉"),
681
- multiple=False,
682
- border=None,
683
- rows=5,
684
- dont_extend_width=False,
685
- )
686
- self.to_focus = options_specs
687
-
688
- connection_files = {
689
- path.name: path
690
- for path in Path(jupyter_runtime_dir()).glob("kernel-*.json")
691
- }
692
- options_files = Select(
693
- options=list(connection_files.values()),
694
- labels=list(connection_files.keys()),
695
- style="class:input,radio-buttons",
696
- prefix=("○", "◉"),
697
- multiple=False,
698
- border=None,
699
- rows=5,
700
- dont_extend_width=False,
701
- )
702
-
703
- msg_ft = (f"{message}\n\n" if message else "") + "Please select a kernel:"
649
+ infos = list_kernels()
650
+ infos_by_kind: dict[str, list[KernelInfo]] = {}
651
+ for info in infos:
652
+ infos_by_kind.setdefault(info.kind, []).append(info)
653
+
654
+ selects = {}
655
+ for kind, infos in infos_by_kind.items():
656
+ selects[kind] = Select(
657
+ options=infos,
658
+ labels=[info.display_name for info in infos],
659
+ style="class:input,radio-buttons",
660
+ prefix=("○", "◉"),
661
+ multiple=False,
662
+ border=None,
663
+ rows=5,
664
+ dont_extend_width=False,
665
+ )
704
666
 
705
667
  self.body = HSplit(
706
668
  [
707
- Label(msg_ft),
669
+ Label(
670
+ (f"{message}\n\n" if message else "") + "Please select a kernel:"
671
+ ),
708
672
  tabs := TabbedSplit(
709
- [
710
- FocusedStyle(options_specs),
711
- FocusedStyle(options_files),
712
- ],
713
- titles=["New", "Existing"],
673
+ [FocusedStyle(select) for select in selects.values()],
674
+ titles=[kind.title() for kind in selects],
714
675
  width=Dimension(min=30),
715
676
  ),
716
677
  ]
@@ -719,15 +680,9 @@ class SelectKernelDialog(Dialog):
719
680
  def _change_kernel() -> None:
720
681
  self.hide()
721
682
  assert tab is not None
722
- if tabs.active == 0:
723
- name = options_specs.value
724
- connection_file = None
725
- else:
726
- name = None
727
- connection_file = options_files.value
728
- tab.kernel.change(
729
- name=name, connection_file=connection_file, cb=tab.kernel_started
730
- )
683
+ if (index := tabs.active) is not None:
684
+ info = list(selects.values())[index].value
685
+ tab.switch_kernel(info.factory)
731
686
 
732
687
  self.buttons = {
733
688
  "Select": _change_kernel,
@@ -834,7 +789,36 @@ class ErrorDialog(Dialog):
834
789
  def _copy_traceback() -> None:
835
790
  self.app.clipboard.set_data(ClipboardData(tb_text))
836
791
 
837
- self.buttons = {"Close": None, "Copy Traceback": _copy_traceback}
792
+ def _report() -> None:
793
+ import webbrowser
794
+ from importlib.metadata import metadata
795
+ from urllib.parse import urlencode, urlparse, urlunparse
796
+
797
+ data = metadata("euporie")
798
+ if issue_url := dict(
799
+ x.split(", ", 1) for x in data.json["project_url"]
800
+ ).get("Issues"):
801
+ parsed_url = urlparse(issue_url)
802
+ url = urlunparse(
803
+ parsed_url._replace(
804
+ path=f"{parsed_url.path.rstrip('/')}/new"
805
+ )._replace(
806
+ query=urlencode(
807
+ {
808
+ "title": f"Error: {exception!r}",
809
+ "body": "(Please describe what you did)\n\n"
810
+ f"## Traceback\n\n```python\n{tb_text}\n```\n",
811
+ }
812
+ )
813
+ )
814
+ )
815
+ webbrowser.open(url, new=2, autoraise=True)
816
+
817
+ self.buttons = {
818
+ "Report on GitHub": _report,
819
+ "Copy Traceback": _copy_traceback,
820
+ "Close": None,
821
+ }
838
822
 
839
823
 
840
824
  class UnsavedDialog(Dialog):
@@ -2,6 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import asyncio
5
6
  import logging
6
7
  from functools import partial
7
8
  from math import ceil
@@ -28,7 +29,6 @@ from euporie.core.key_binding.registry import (
28
29
  )
29
30
  from euporie.core.layout.containers import VSplit, Window
30
31
  from euporie.core.margins import MarginContainer, ScrollbarMargin
31
- from euporie.core.utils import run_in_thread_with_context
32
32
 
33
33
  if TYPE_CHECKING:
34
34
  from collections.abc import Iterable
@@ -217,7 +217,7 @@ class DisplayControl(UIControl):
217
217
  if not self.rendering:
218
218
  self.rendering = True
219
219
  if self.threaded:
220
- run_in_thread_with_context(_render)
220
+ get_app().create_background_task(asyncio.to_thread(_render))
221
221
  else:
222
222
  _render()
223
223
 
@@ -11,17 +11,19 @@ from math import ceil, floor
11
11
  from typing import TYPE_CHECKING, cast
12
12
  from weakref import finalize
13
13
 
14
- from prompt_toolkit.buffer import ValidationState
14
+ from prompt_toolkit.auto_suggest import DynamicAutoSuggest
15
+ from prompt_toolkit.buffer import Buffer, ValidationState
15
16
  from prompt_toolkit.cache import SimpleCache
16
- from prompt_toolkit.completion.base import ConditionalCompleter
17
- from prompt_toolkit.completion.word_completer import WordCompleter
17
+ from prompt_toolkit.completion import Completer, ConditionalCompleter, WordCompleter
18
18
  from prompt_toolkit.data_structures import Point
19
+ from prompt_toolkit.document import Document
19
20
  from prompt_toolkit.filters import (
20
21
  Always,
21
22
  Condition,
22
23
  Filter,
23
24
  FilterOrBool,
24
25
  has_focus,
26
+ is_true,
25
27
  to_filter,
26
28
  )
27
29
  from prompt_toolkit.formatted_text.base import to_formatted_text
@@ -39,13 +41,19 @@ from prompt_toolkit.layout.controls import (
39
41
  UIControl,
40
42
  )
41
43
  from prompt_toolkit.layout.dimension import Dimension
42
- from prompt_toolkit.layout.processors import AfterInput, ConditionalProcessor
44
+ from prompt_toolkit.layout.processors import (
45
+ AfterInput,
46
+ BeforeInput,
47
+ ConditionalProcessor,
48
+ PasswordProcessor,
49
+ Processor,
50
+ )
43
51
  from prompt_toolkit.layout.screen import WritePosition
44
52
  from prompt_toolkit.layout.utils import explode_text_fragments
53
+ from prompt_toolkit.lexers import DynamicLexer, Lexer
45
54
  from prompt_toolkit.mouse_events import MouseButton, MouseEvent, MouseEventType
46
55
  from prompt_toolkit.utils import Event
47
56
  from prompt_toolkit.validation import Validator
48
- from prompt_toolkit.widgets.base import TextArea
49
57
 
50
58
  from euporie.core.app.current import get_app
51
59
  from euporie.core.border import InsetGrid
@@ -59,7 +67,8 @@ if TYPE_CHECKING:
59
67
  from collections.abc import Sequence
60
68
  from typing import Any, Callable
61
69
 
62
- from prompt_toolkit.buffer import Buffer, BufferAcceptHandler
70
+ from prompt_toolkit.auto_suggest import AutoSuggest
71
+ from prompt_toolkit.buffer import BufferAcceptHandler
63
72
  from prompt_toolkit.completion.base import Completer
64
73
  from prompt_toolkit.formatted_text.base import (
65
74
  AnyFormattedText,
@@ -498,6 +507,7 @@ class ExpandingBufferControl(BufferControl):
498
507
  focus_on_click: FilterOrBool = False,
499
508
  key_bindings: KeyBindingsBase | None = None,
500
509
  expand: FilterOrBool = True,
510
+ on_focus: Callable[[], None] | None = None,
501
511
  ) -> None:
502
512
  """Add an ``expand`` parameter to the buffer control."""
503
513
  super().__init__(
@@ -513,6 +523,7 @@ class ExpandingBufferControl(BufferControl):
513
523
  key_bindings=key_bindings,
514
524
  )
515
525
  self.expand = to_filter(expand)
526
+ self.on_focus = on_focus
516
527
 
517
528
  def preferred_width(self, max_available_width: int) -> int | None:
518
529
  """Enure text box expands to available width.
@@ -528,6 +539,16 @@ class ExpandingBufferControl(BufferControl):
528
539
  else:
529
540
  return None
530
541
 
542
+ def mouse_handler(self, mouse_event: MouseEvent) -> NotImplementedOrNone:
543
+ """Optionally call focus handler when focused."""
544
+ layout = get_app().layout
545
+ was_focused = layout.current_control == self
546
+ result = super().mouse_handler(mouse_event)
547
+ is_focused = layout.current_control == self
548
+ if not was_focused and is_focused and callable(self.on_focus):
549
+ self.on_focus()
550
+ return result
551
+
531
552
 
532
553
  class Text:
533
554
  """A text input widget."""
@@ -554,6 +575,9 @@ class Text:
554
575
  password: FilterOrBool = False,
555
576
  wrap_lines: FilterOrBool = False,
556
577
  prompt: AnyFormattedText | None = None,
578
+ on_focus: Callable[[], None] | None = None,
579
+ complete_while_typing: FilterOrBool = True,
580
+ auto_suggest: AutoSuggest | None = None,
557
581
  ) -> None:
558
582
  """Create a new text widget instance.
559
583
 
@@ -580,33 +604,44 @@ class Text:
580
604
  disabled: A filter which when evaluated to :py:const:`True` causes the
581
605
  widget to be disabled
582
606
  password: A filter to determine if the text input is a password field
583
- prompt: Text to display before the input
584
607
  wrap_lines: Whether to wrap lines wider than the text area
608
+ prompt: Text to display before the input
609
+ on_focus: Function to call when the buffer gains focus
610
+ complete_while_typing: Whether to show completions while typing
611
+ auto_suggest: Auto-suggestion behavior for the text input
585
612
  """
586
613
  self.style = style
587
614
  self.options = options or []
588
615
  self.disabled = to_filter(disabled)
589
-
590
616
  self.placeholder = placeholder
617
+ self.wrap_lines = wrap_lines
618
+ self.complete_while_typing = complete_while_typing
619
+ self.auto_suggest = auto_suggest
620
+ self.lexer = lexer
591
621
 
592
- self.text_area = TextArea(
593
- str(text),
622
+ self.buffer = Buffer(
623
+ document=Document(str(text), 0),
594
624
  multiline=multiline,
595
- height=Dimension(min=min_height, max=height, preferred=height),
596
- width=width,
597
- focusable=~self.disabled,
598
- focus_on_click=~self.disabled,
599
625
  read_only=self.disabled,
600
- style=f"{style} class:text,text-area",
601
- validator=Validator.from_callable(validation) if validation else None,
602
- accept_handler=accept_handler,
603
626
  completer=completer
604
627
  or ConditionalCompleter(
605
628
  WordCompleter(self.options),
606
629
  filter=Condition(lambda: bool(self.options)),
607
630
  ),
608
- lexer=lexer,
631
+ complete_while_typing=Condition(
632
+ lambda: is_true(self.complete_while_typing)
633
+ ),
634
+ validator=Validator.from_callable(validation) if validation else None,
635
+ validate_while_typing=validation is not None,
636
+ auto_suggest=DynamicAutoSuggest(lambda: self.auto_suggest),
637
+ accept_handler=accept_handler,
638
+ )
639
+
640
+ self.control = ExpandingBufferControl(
641
+ buffer=self.buffer,
642
+ lexer=DynamicLexer(lambda: self.lexer),
609
643
  input_processors=[
644
+ BeforeInput(prompt, style="class:text-area.prompt"),
610
645
  ConditionalProcessor(
611
646
  AfterInput(
612
647
  lambda: self.placeholder, style="class:text,placeholder"
@@ -615,58 +650,35 @@ class Text:
615
650
  lambda: self.placeholder is not None and self.buffer.text == ""
616
651
  ),
617
652
  ),
653
+ ConditionalProcessor(
654
+ processor=PasswordProcessor(), filter=to_filter(password)
655
+ ),
618
656
  *(input_processors or []),
619
657
  ],
620
- password=password,
621
- wrap_lines=wrap_lines,
622
- )
623
- self.buffer = self.text_area.buffer
624
-
625
- # Patch text area control's to expand to fill available width
626
- # Do this without monkey-pathing by sub-classing :class:`BufferControl` and
627
- # re-assigning the text-area's control
628
- self.text_area.control = ExpandingBufferControl(
629
- buffer=self.text_area.control.buffer,
630
- input_processors=self.text_area.control.input_processors,
631
- include_default_input_processors=(
632
- self.text_area.control.include_default_input_processors
633
- ),
634
- lexer=self.text_area.control.lexer,
635
- preview_search=self.text_area.control.preview_search,
636
- focusable=self.text_area.control.focusable,
637
- search_buffer_control=self.text_area.control._search_buffer_control,
638
- menu_position=self.text_area.control.menu_position,
639
- focus_on_click=self.text_area.control.focus_on_click,
640
- key_bindings=self.text_area.control.key_bindings,
658
+ focusable=~self.disabled,
659
+ focus_on_click=~self.disabled,
641
660
  expand=expand,
661
+ on_focus=on_focus,
642
662
  )
643
- window = self.text_area.window
644
- self.text_area.window = Window(
645
- height=window.height,
646
- width=window.width,
647
- dont_extend_height=window.dont_extend_height,
648
- dont_extend_width=window.dont_extend_width,
649
- content=self.text_area.control,
650
- style=window.style,
651
- wrap_lines=window.wrap_lines,
652
- left_margins=window.left_margins,
653
- right_margins=window.right_margins,
654
- get_line_prefix=window.get_line_prefix,
663
+
664
+ self.window = Window(
665
+ height=Dimension(min=min_height, max=height, preferred=height),
666
+ width=width,
667
+ content=self.control,
668
+ wrap_lines=Condition(lambda: is_true(self.wrap_lines)),
669
+ style=f"{style} class:text,text-area",
655
670
  )
656
- self.text_area.window.content = self.text_area.control
657
671
 
658
672
  if on_text_changed:
659
- self.text_area.buffer.on_text_changed += on_text_changed
673
+ self.buffer.on_text_changed += on_text_changed
660
674
  if validation:
661
- self.text_area.buffer.validate_while_typing = Always()
675
+ self.buffer.validate_while_typing = Always()
662
676
  self.container = Border(
663
677
  VSplit(
664
678
  [
665
- self.text_area,
679
+ self.window,
666
680
  ConditionalContainer(
667
- MarginContainer(
668
- ScrollbarMargin(), target=self.text_area.window
669
- ),
681
+ MarginContainer(ScrollbarMargin(), target=self.window),
670
682
  filter=to_filter(multiline),
671
683
  ),
672
684
  ]
@@ -678,7 +690,7 @@ class Text:
678
690
 
679
691
  def border_style(self) -> str:
680
692
  """Calculate the style to apply to the widget's border."""
681
- if self.text_area.buffer.validation_state == ValidationState.INVALID:
693
+ if self.buffer.validation_state == ValidationState.INVALID:
682
694
  return f"{self.style} class:text,border,invalid"
683
695
  else:
684
696
  return f"{self.style} class:text,border"
@@ -250,7 +250,10 @@ class KernelInput(TextArea):
250
250
  buffer=self.buffer,
251
251
  lexer=DynamicLexer(
252
252
  lambda: _get_lexer(
253
- app.config.syntax_highlighting, self.lexer, self.language
253
+ # Only lex buffers with text
254
+ self.buffer.text and app.config.syntax_highlighting,
255
+ self.lexer,
256
+ self.language,
254
257
  )
255
258
  ),
256
259
  input_processors=[
@@ -506,7 +509,7 @@ class StdInput:
506
509
  password=Condition(lambda: self.password),
507
510
  style="class:input",
508
511
  )
509
- self.window = text.text_area.window
512
+ self.window = text.window
510
513
  self.container = ConditionalContainer(
511
514
  LabelledWidget(
512
515
  body=text,
@@ -517,8 +520,8 @@ class StdInput:
517
520
 
518
521
  def accept(self, buffer: Buffer) -> bool:
519
522
  """Send the input to the kernel and hide the input box."""
520
- if self.kernel_tab.kernel.kc is not None:
521
- self.kernel_tab.kernel.kc.input(buffer.text)
523
+ if self.kernel_tab.kernel is not None:
524
+ self.kernel_tab.kernel.input(buffer.text)
522
525
  # Cleanup
523
526
  self.active = False
524
527