Example #1
0
    def initialize(self):
        prefs = Preferences

        self.ignore_text_changed = False

        g = self.root = wpf.Grid()

        cd = wpf.ColumnDefinition()
        cd.Width = wpf.GridLength(1, wpf.GridUnitType.Star)
        g.ColumnDefinitions.Add(cd)
        cd = wpf.ColumnDefinition()
        cd.Width = wpf.GridLength(0, wpf.GridUnitType.Auto)
        g.ColumnDefinitions.Add(cd)

        self.canvas = wpf.Create(
            wpf.Canvas,
            Grid_Row=0,
            Grid_Column=1,
            Background=wpf.brush(wpf.Colors.White),
            Margin=wpf.Thickness(5, 0, 0, 0),
        )
        g.Children.Add(self.canvas)

        self.sv = wpf.Create(wpf.ScrollViewer, Grid_Row=0, Grid_Column=0, Padding=wpf.Thickness(5))
        g.Children.Add(self.sv)

        g.Children.Add(
            wpf.Create(
                wpf.GridSplitter,
                Grid_Row=0,
                Grid_Column=1,
                Width=5,
                HorizontalAlignment=wpf.HorizontalAlignment.Left,
                VerticalAlignment=wpf.VerticalAlignment.Stretch,
                Background=wpf.brush(wpf.Colors.MidnightBlue),
            )
        )

        prefs.apply_to(g, "BackgroundImage", "Background")
        prefs.apply_to(self.sv, "BackgroundMask", "Background")

        g = self.sv.Content = wpf.Grid()

        rd = wpf.RowDefinition()
        rd.Height = wpf.GridLength(0, wpf.GridUnitType.Auto)
        g.RowDefinitions.Add(rd)
        rd = wpf.RowDefinition()
        rd.Height = wpf.GridLength(1, wpf.GridUnitType.Auto)
        g.RowDefinitions.Add(rd)

        cd = wpf.ColumnDefinition()
        cd.Width = wpf.GridLength(0, wpf.GridUnitType.Auto)
        g.ColumnDefinitions.Add(cd)
        cd = wpf.ColumnDefinition()
        cd.Width = wpf.GridLength(1, wpf.GridUnitType.Star)
        g.ColumnDefinitions.Add(cd)

        self.buffer = wpf.TextBox()
        self.prompt = wpf.TextBox()
        self.ps = wpf.TextBlock()
        self.ps.Text = sys.ps1

        self.buffer.AcceptsReturn = self.prompt.AcceptsReturn = True
        self.buffer.TextWrapping = wpf.TextWrapping.Wrap
        self.buffer.IsReadOnly = True

        if sys.platform == "silverlight":
            self.prompt.SelectionForeground = self.buffer.SelectionForeground = wpf.brush("#000000")
            self.prompt.SelectionBackground = self.buffer.SelectionBackground = wpf.brush("#00ffff")
        else:
            self.ps.Margin = wpf.Thickness(2, 0, 0, 0)

        prefs.apply_style_to(self.buffer, "TextBoxStyle")
        prefs.apply_style_to(self.prompt, "TextBoxStyle")

        for tbx in (self.buffer, self.prompt, self.ps):
            prefs.apply_to(tbx, "FontSize")
            prefs.apply_to(tbx, "FontFamily")
            prefs.apply_to(tbx, "FontWeight")
            prefs.apply_to(tbx, "Foreground")

        wpf.Grid.SetColumn(self.buffer, 0)
        wpf.Grid.SetColumnSpan(self.buffer, 2)
        wpf.Grid.SetRow(self.buffer, 0)
        g.Children.Add(self.buffer)

        wpf.Grid.SetColumn(self.ps, 0)
        wpf.Grid.SetRow(self.ps, 1)
        g.Children.Add(self.ps)

        wpf.Grid.SetColumn(self.prompt, 1)
        wpf.Grid.SetRow(self.prompt, 1)
        g.Children.Add(self.prompt)

        pnl = wpf.Create(
            wpf.StackPanel,
            Grid_Row=0,
            Grid_Column=1,
            Orientation=wpf.Orientation.Vertical,
            HorizontalAlignment=wpf.HorizontalAlignment.Right,
            VerticalAlignment=wpf.VerticalAlignment.Top,
        )

        btn = wpf.Create(wpf.Button, Content="Preferences")
        prefs.apply_style_to(btn, "ButtonStyle")
        btn.Click += self.OnPreferencesClick
        pnl.Children.Add(btn)

        btn = wpf.Create(wpf.Button, Content=("Background Thread" if prefs.BackgroundExecution else "UI Thread"))
        prefs.apply_style_to(btn, "ButtonStyle")
        btn.Click += self.OnChangeThread
        pnl.Children.Add(btn)

        g.Children.Add(pnl)

        self.redirect_stdstreams()

        self.cursor = Cursor(self.prompt, self.sv)

        self.intellisense = Intellisense(self.engine, self.prompt)  # Must come before other KeyDown handlers
        if sys.platform == "cli":
            self.prompt.PreviewKeyDown += self.OnKeyDown
        else:
            self.prompt.KeyDown += self.OnKeyDown

        self.prompt.TextChanged += self.OnTextChanged
Example #2
0
class SilverShell(object):
    def __init__(self):
        self.engine = SilverShellEngine()

        self.initialize()

        self.engine.namespace["canvas"] = self.canvas
        self.engine.write_banner()

        self.engine.Reset += self.OnEngineReset
        Preferences.Changed += self.OnPreferencesChanged

    def initialize(self):
        prefs = Preferences

        self.ignore_text_changed = False

        g = self.root = wpf.Grid()

        cd = wpf.ColumnDefinition()
        cd.Width = wpf.GridLength(1, wpf.GridUnitType.Star)
        g.ColumnDefinitions.Add(cd)
        cd = wpf.ColumnDefinition()
        cd.Width = wpf.GridLength(0, wpf.GridUnitType.Auto)
        g.ColumnDefinitions.Add(cd)

        self.canvas = wpf.Create(
            wpf.Canvas,
            Grid_Row=0,
            Grid_Column=1,
            Background=wpf.brush(wpf.Colors.White),
            Margin=wpf.Thickness(5, 0, 0, 0),
        )
        g.Children.Add(self.canvas)

        self.sv = wpf.Create(wpf.ScrollViewer, Grid_Row=0, Grid_Column=0, Padding=wpf.Thickness(5))
        g.Children.Add(self.sv)

        g.Children.Add(
            wpf.Create(
                wpf.GridSplitter,
                Grid_Row=0,
                Grid_Column=1,
                Width=5,
                HorizontalAlignment=wpf.HorizontalAlignment.Left,
                VerticalAlignment=wpf.VerticalAlignment.Stretch,
                Background=wpf.brush(wpf.Colors.MidnightBlue),
            )
        )

        prefs.apply_to(g, "BackgroundImage", "Background")
        prefs.apply_to(self.sv, "BackgroundMask", "Background")

        g = self.sv.Content = wpf.Grid()

        rd = wpf.RowDefinition()
        rd.Height = wpf.GridLength(0, wpf.GridUnitType.Auto)
        g.RowDefinitions.Add(rd)
        rd = wpf.RowDefinition()
        rd.Height = wpf.GridLength(1, wpf.GridUnitType.Auto)
        g.RowDefinitions.Add(rd)

        cd = wpf.ColumnDefinition()
        cd.Width = wpf.GridLength(0, wpf.GridUnitType.Auto)
        g.ColumnDefinitions.Add(cd)
        cd = wpf.ColumnDefinition()
        cd.Width = wpf.GridLength(1, wpf.GridUnitType.Star)
        g.ColumnDefinitions.Add(cd)

        self.buffer = wpf.TextBox()
        self.prompt = wpf.TextBox()
        self.ps = wpf.TextBlock()
        self.ps.Text = sys.ps1

        self.buffer.AcceptsReturn = self.prompt.AcceptsReturn = True
        self.buffer.TextWrapping = wpf.TextWrapping.Wrap
        self.buffer.IsReadOnly = True

        if sys.platform == "silverlight":
            self.prompt.SelectionForeground = self.buffer.SelectionForeground = wpf.brush("#000000")
            self.prompt.SelectionBackground = self.buffer.SelectionBackground = wpf.brush("#00ffff")
        else:
            self.ps.Margin = wpf.Thickness(2, 0, 0, 0)

        prefs.apply_style_to(self.buffer, "TextBoxStyle")
        prefs.apply_style_to(self.prompt, "TextBoxStyle")

        for tbx in (self.buffer, self.prompt, self.ps):
            prefs.apply_to(tbx, "FontSize")
            prefs.apply_to(tbx, "FontFamily")
            prefs.apply_to(tbx, "FontWeight")
            prefs.apply_to(tbx, "Foreground")

        wpf.Grid.SetColumn(self.buffer, 0)
        wpf.Grid.SetColumnSpan(self.buffer, 2)
        wpf.Grid.SetRow(self.buffer, 0)
        g.Children.Add(self.buffer)

        wpf.Grid.SetColumn(self.ps, 0)
        wpf.Grid.SetRow(self.ps, 1)
        g.Children.Add(self.ps)

        wpf.Grid.SetColumn(self.prompt, 1)
        wpf.Grid.SetRow(self.prompt, 1)
        g.Children.Add(self.prompt)

        pnl = wpf.Create(
            wpf.StackPanel,
            Grid_Row=0,
            Grid_Column=1,
            Orientation=wpf.Orientation.Vertical,
            HorizontalAlignment=wpf.HorizontalAlignment.Right,
            VerticalAlignment=wpf.VerticalAlignment.Top,
        )

        btn = wpf.Create(wpf.Button, Content="Preferences")
        prefs.apply_style_to(btn, "ButtonStyle")
        btn.Click += self.OnPreferencesClick
        pnl.Children.Add(btn)

        btn = wpf.Create(wpf.Button, Content=("Background Thread" if prefs.BackgroundExecution else "UI Thread"))
        prefs.apply_style_to(btn, "ButtonStyle")
        btn.Click += self.OnChangeThread
        pnl.Children.Add(btn)

        g.Children.Add(pnl)

        self.redirect_stdstreams()

        self.cursor = Cursor(self.prompt, self.sv)

        self.intellisense = Intellisense(self.engine, self.prompt)  # Must come before other KeyDown handlers
        if sys.platform == "cli":
            self.prompt.PreviewKeyDown += self.OnKeyDown
        else:
            self.prompt.KeyDown += self.OnKeyDown

        self.prompt.TextChanged += self.OnTextChanged

    def Dispose(self):
        self.cursor.Dispose()
        self.intellisense.Dispose()

    def redirect_stdstreams(self):
        self.engine.strm = sys.stdout = TextBoxStream(self.buffer)
        sys.stderr = sys.stdout  # comment this out to see exceptions at system console

    def start(self):
        self.ps.Text = sys.ps1
        self.prompt.Text = ""
        self.prompt.Focus()

    def scroll_to_bottom(self):
        self.sv.UpdateLayout()
        if self.sv.ViewportHeight:
            self.sv.ScrollToVerticalOffset(self.sv.ScrollableHeight)

    def fix_paste(self):
        l = []
        for line in self.prompt.Text.splitlines():
            if line.startswith((sys.ps1, sys.ps2)):
                line = line[4:]

            l.append(line)

        self.prompt.Text = "\n".join(l)
        self.prompt.SelectionStart = len(self.prompt.Text)

    def indent(self):
        pos, end, line = self.get_current_line()
        # Don't insert indentation unless we're at the beginning of the line
        if not self.prompt.Text[end - len(line) : pos].strip():
            self.prompt.Text = self.prompt.Text[:pos] + " " * 4 + self.prompt.Text[pos:]
            self.prompt.SelectionStart = pos + 4

    def get_current_line(self):
        return utils.get_current_line(self.prompt)

    def history(self, delta=None):
        pos, end, line = self.get_current_line()
        # Don't insert a history item unless we're at an empty line, or the line is located in history
        if delta is not None and line.strip() and line.lstrip() not in self.engine.history:
            return False
        else:
            # Preserve the indentation
            indent = line[: -len(line.lstrip())] if line.strip() else line
            start = end - len(line)
            if delta is None:
                try:
                    history = self.engine.history.find(line)
                except ValueError:
                    return True
            else:
                history = self.engine.history.go(delta)

            line = indent + history
            self.prompt.Text = self.prompt.Text[:start] + line + self.prompt.Text[end:]
            self.prompt.SelectionStart = start + len(line)
            return True

    def clear_prompt(self):
        self.prompt.Text = ""
        self.ps.Text = sys.ps1
        self.scroll_to_bottom()
        self.cursor.update()

    def continue_prompt(self):
        self.ignore_text_changed = True
        self.ps.Text += "\n" + sys.ps2
        pos = self.prompt.SelectionStart
        self.prompt.Text = self.prompt.Text[:pos] + "\n" + " " * 4 + self.prompt.Text[pos:]
        self.prompt.SelectionStart = pos + 5
        self.scroll_to_bottom()
        self.ignore_text_changed = False

    def interpret(self):
        if not self.engine.run(self.prompt.Text):
            self.clear_prompt()
        else:
            self.continue_prompt()

    def OnEngineReset(self, sender, e):
        sys.stdout.reset()
        self.engine.namespace["canvas"] = self.canvas
        self.start()

    def OnKeyDown(self, sender, e):
        if e.Key == wpf.Key.Enter:
            self.interpret()
            e.Handled = True  # we insert the newline ourselves
        elif e.Key == wpf.Key.Up:
            e.Handled = self.history(-1)
        elif e.Key == wpf.Key.Down:
            e.Handled = self.history(1)
        elif e.Key == wpf.Key.Tab:
            if wpf.Keyboard.Modifiers & wpf.ModifierKeys.Shift:
                e.Handled = self.history()
            else:
                e.Handled = self.intellisense.complete()
                if not e.Handled:
                    self.indent()
                    e.Handled = True

    def OnTextChanged(self, sender, e):
        if not self.ignore_text_changed:
            num_lines = self.prompt.Text.count("\n") + 1
            ps_lines = self.ps.Text.count("\n") + 1
            if num_lines != ps_lines:
                self.ps.Text = "\n".join(
                    itertools.islice(itertools.chain(self.ps.Text.splitlines(), itertools.repeat(sys.ps2)), num_lines)
                )

                if num_lines > ps_lines:
                    # Maybe a paste, so we have to remove prompts and normalize newlines
                    self.fix_paste()

    def OnPreferencesClick(self, sender, e):
        Preferences.show()

    def OnChangeThread(self, sender, e):
        if sender.Content == "UI Thread":
            sender.Content = "Background Thread"
            self.engine.use_background_thread()
        else:
            sender.Content = "UI Thread"
            self.engine.use_ui_thread()

    def OnPreferencesChanged(self, sender, e):
        parent = self.root.Parent
        self.Dispose()
        self.initialize()
        wpf.LogicalTree.SetContent(parent, self.root)
        self.engine.reset()

    def GetVisualRoot(self):
        return self.root