PoshCode Logo PowerShell Code Repository

BufferBox 3.0 by Joel Bennett 3 years ago (modification of post by Joel Bennett view diff)
View followups from Joel Bennett | diff | embed code: <script type="text/javascript" src="http://PoshCode.org/embed/2238"></script>download | new post

Some functions for drawing mini-buffers. Please try the two demo functions included!

  1. ####################################################################################################
  2. ## This script is just a demonstration of some of the things you can do with the buffer
  3. ## in the default PowerShell host... it serves as a reminder of how much work remains on
  4. ## PoshConsole, and as an inspirations to anyone who is thinking about trying to create
  5. ## "interactive" PowerShell applications.
  6. ##
  7. ####################################################################################################
  8. $global:BoxChars = new-object PSObject -Property @{
  9.    'HorizontalDouble'            = ([char]9552).ToString()
  10.    'VerticalDouble'              = ([char]9553).ToString()
  11.    'TopLeftDouble'               = ([char]9556).ToString()
  12.    'TopRightDouble'              = ([char]9559).ToString()
  13.    'BottomLeftDouble'            = ([char]9562).ToString()
  14.    'BottomRightDouble'           = ([char]9565).ToString()
  15.    'HorizontalDoubleSingleDown'  = ([char]9572).ToString()
  16.    'HorizontalDoubleSingleUp'    = ([char]9575).ToString()
  17.    'Horizontal'                  = ([char]9472).ToString()
  18.    'Vertical'                    = ([char]9474).ToString()
  19.    'TopLeft'                     = ([char]9484).ToString()
  20.    'TopRight'                    = ([char]9488).ToString()
  21.    'BottomLeft'                  = ([char]9492).ToString()
  22.    'BottomRight'                 = ([char]9496).ToString()
  23.    'Cross'                       = ([char]9532).ToString()
  24.    'VerticalDoubleRightSingle'   = ([char]9567).ToString()
  25.    'VerticalDoubleLeftSingle'    = ([char]9570).ToString()
  26. }
  27. $global:RectType = "system.management.automation.host.rectangle"
  28.  
  29. function Reset-Buffer {
  30. param(
  31.    $Position = $Host.UI.RawUI.WindowPosition,
  32.    [int]$Height = $Host.UI.RawUI.WindowSize.Height,
  33.    [int]$Width = $Host.UI.RawUI.WindowSize.Width,
  34.    # Note: all edges are padded by 1 for the box edges, but we also pad each side by this ammount:
  35.    [int]$Padding = 1,
  36.    $ForegroundColor = $Host.UI.RawUI.ForegroundColor,
  37.    $BackgroundColor = $Host.UI.RawUI.BackgroundColor,
  38.    $BorderColor     = "Yellow",
  39.    [switch]$NoBorder,
  40.    [switch]$ShowInput,
  41.    [string]$Title = ""
  42. )
  43.  
  44. $global:BufferHeight          = $Height
  45. $global:BufferWidth           = $Width
  46. $global:BufferPadding         = $Padding
  47. $global:BufferForegroundColor = $ForegroundColor
  48. $global:BufferBackgroundColor = $BackgroundColor
  49. $global:BufferBorderColor     = $BorderColor    
  50.  
  51.    if($NoBorder) {
  52.       $global:BufferBoxSides = 0
  53.    } else {
  54.       $global:BufferBoxSides = 2
  55.    }
  56.    if($ShowInput) {
  57.       $global:BufferHeight -= 2
  58.    }
  59.  
  60.    $Host.UI.RawUI.SetBufferContents($Position,(New-BufferBox $BufferHeight $BufferWidth -Title:$Title -NoBorder:$NoBorder -ShowInput:$ShowInput -Background $BufferBackgroundColor -Border $BufferBorderColor))
  61.  
  62.    
  63.    $global:BufferPosition = $Position  
  64.    $global:BufferPosition.X += $global:BufferPadding + ($global:BufferBoxSides/2)
  65.    # this gets set to the BOTTOM line, because I assume text will flow in from the bottom.
  66.    $global:BufferPosition.Y += $global:BufferHeight - 2
  67.    # and this goes below that ...
  68.    $global:BufferPromptPosition = $BufferPosition
  69.    $global:BufferPromptPosition.Y += 2
  70.    $global:BufferPromptPosition.X += 2 - $global:BufferPadding # Prompt = "> "
  71. }
  72.  
  73. function New-BufferBox {
  74. param(
  75.    [int]$Height = $global:BufferHeight,
  76.    [int]$Width = $global:BufferWidth,
  77.    $Title = "",
  78.    [switch]$NoBorder,
  79.    [switch]$ShowInput,
  80.    $BackgroundColor = $global:BufferBackgroundColor,
  81.    $BorderColor = $global:BufferBorderColor
  82. )
  83.    $Width = $Width - $global:BufferBoxSides
  84.    
  85.    $LineTop =( $global:BoxChars.HorizontalDouble * 2) + $Title `
  86.             + $($global:BoxChars.HorizontalDouble * ($Width - ($Title.Length+2)))
  87.    
  88.    $LineField = ' ' * $Width
  89.    $LineBottom = $global:BoxChars.HorizontalDouble * $Width
  90.    $LineSeparator = $global:BoxChars.Horizontal * $Width
  91.    $LinePrompt = '> ' + ' ' * ($Width-2) # Prompt = "> "
  92.    
  93.    if(!$NoBorder) {
  94.       $LineField = $global:BoxChars.VerticalDouble + $LineField + $global:BoxChars.VerticalDouble
  95.       $LinePrompt = $global:BoxChars.VerticalDouble + $LinePrompt + $global:BoxChars.VerticalDouble
  96.       $LineBottom = $global:BoxChars.BottomLeftDouble + $LineBottom + $global:BoxChars.BottomRightDouble
  97.       $LineTop = $global:BoxChars.TopLeftDouble + $LineTop + $global:BoxChars.TopRightDouble
  98.       $LineSeparator = $global:BoxChars.VerticalDoubleRightSingle + $LineSeparator + $global:BoxChars.VerticalDoubleLeftSingle
  99.    }
  100.  
  101.    if($ShowInput) {
  102.       $box = &{$LineTop;1..($Height - 2) |% {$LineField};$LineSeparator;$LinePrompt;$LineBottom}
  103.    } else {
  104.       $box = &{$LineTop;1..($Height - 2) |% {$LineField};$LineBottom}
  105.    }
  106.    $boxBuffer = $Host.UI.RawUI.NewBufferCellArray($box,$BorderColor,$BackgroundColor)
  107.    return ,$boxBuffer
  108. }
  109.  
  110. function Move-Buffer {
  111. param(
  112.    $Position = $global:BufferPosition,
  113.    [int]$Left = $($global:BufferBoxSides/2),
  114.    [int]$Top = (2 - $global:BufferHeight),
  115.    [int]$Width = $global:BufferWidth - $global:BufferBoxSides,
  116.    [int]$Height = $global:BufferHeight,
  117.    [int]$Offset = -1
  118. )
  119.    $Position.X += $Left
  120.    $Position.Y += $Top
  121.    $Rect = New-Object $RectType $Position.X, $Position.Y, ($Position.X + $width), ($Position.Y + $height -1)
  122.    $Position.Y += $OffSet
  123.    $Host.UI.RawUI.ScrollBufferContents($Rect, $Position, $Rect, (new-object System.Management.Automation.Host.BufferCell(' ',$global:BufferForegroundColor,$global:BufferBackgroundColor,'complete')))
  124. }
  125.  
  126. function Out-Buffer {
  127. param(
  128.    [Parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
  129.    $Message,
  130.    [Parameter(ValueFromPipelineByPropertyName=$true)]
  131.    $ForegroundColor = $global:BufferForegroundColor,
  132.    [Parameter(ValueFromPipelineByPropertyName=$true)]
  133.    $BackgroundColor = $global:BufferBackgroundColor,
  134.    
  135.    [switch]$NoScroll,
  136.    
  137.    [Parameter(ValueFromPipelineByPropertyName=$true)]
  138.    $Position = $global:BufferPosition,
  139.    [Parameter(ValueFromPipelineByPropertyName=$true)]
  140.    [int]$Left = 0,
  141.    [Parameter(ValueFromPipelineByPropertyName=$true)]
  142.    [int]$Top    = $(3 - $global:BufferHeight),  # Box Edge + New Lines
  143.    [Parameter(ValueFromPipelineByPropertyName=$true)]
  144.    [int]$Width  = ($global:BufferWidth - $global:BufferBoxSides), # Box Edge
  145.    [Parameter(ValueFromPipelineByPropertyName=$true)]
  146.    [int]$Height = ($global:BufferHeight - $global:BufferBoxSides), # Box Edge
  147.    [Parameter(ValueFromPipelineByPropertyName=$true)]
  148.    [int]$Offset = $( 0 - ($Message.Split("`n").Count))
  149. )
  150. process {
  151.    $lineCount = $Message.Split("`n").Count
  152.  
  153.    $Width = $Width - ($global:BufferPadding * 2)
  154.    if(!$NoScroll){ Move-Buffer $Position $Left $Top $Width $Height $Offset }
  155.    
  156.    $MessageBuffer = New-Object "System.Management.Automation.Host.BufferCell[,]" $lineCount, $width
  157.    
  158.    $index = 0
  159.    foreach( $line in $Message.Split("`n") ) {
  160.       $Buffer = $Host.UI.RawUI.NewBufferCellArray( @($line.Trim("`r").PadRight($Width)), $ForegroundColor, $BackgroundColor )
  161.       for($i = 0; $i -lt $width; $i++) {
  162.          $MessageBuffer[$index,$i] = $Buffer[0,$i]
  163.       }
  164.       $index++
  165.    }
  166.    
  167.    $Y = $global:BufferPosition.Y
  168.    $global:BufferPosition.Y -= $lineCount - 1
  169.    $Host.UI.RawUI.SetBufferContents($global:BufferPosition,$MessageBuffer)
  170.    $global:BufferPosition.Y = $Y
  171. }
  172. }
  173.  
  174. function Set-BufferInputLine {
  175. param([String]$Line = "")
  176.    $PromptText = $line.PadRight(($global:BufferWidth - $line.Length - 3)) # Prompt = "> "
  177.    
  178.    $CursorPosition = $BufferPromptPosition
  179.    $CursorPosition.X += $line.Length
  180.    
  181.    $Prompt = $Host.UI.RawUI.NewBufferCellArray( @($PromptText),$global:BufferForegroundColor, $global:BufferBackgroundColor)
  182.    $Host.UI.RawUI.SetBufferContents( $BufferPromptPosition, $prompt )
  183.    $Host.UI.RawUI.CursorPosition = $CursorPosition
  184. }
  185.  
  186. function Demo1 {
  187.    $Position = $Host.UI.RawUI.WindowPosition
  188.    $Position.X += 10
  189.    $Position.Y += 3
  190.  
  191.    Reset-Buffer $Position 20 66 3 -ForegroundColor 'Gray' -BackgroundColor 'Black' -BorderColor 'Green'
  192.    Out-Buffer 'Greetings!' 'Yellow' 'black'
  193.    sleep -m 600
  194.    Out-Buffer '' 'Gray' 'black'
  195.    sleep -m 600
  196.    Out-Buffer '- - - Thank you for running this simple demo script! - - -' 'Green' 'black'
  197.    sleep -m 600
  198.    Out-Buffer '' 'Gray' 'black'
  199.    sleep -m 600
  200.    Out-Buffer 'We are demonstrating how the scroll buffer works: you can
  201. add more than one line at a time, but you don''t really
  202. need to, since they add almost as fast one at a time.' 'white' 'black'
  203.    sleep -m 3000
  204.    Out-Buffer '' 'Gray' 'black'
  205.    Out-Buffer 'That is, as long as you don''t have any delay, you can just' 'white' 'black'
  206.    Out-Buffer 'write out as many lines as you like, one-at-a-time, like' 'white' 'black'
  207.    Out-Buffer 'this, and there is really no downside to doing that.' 'white' 'black'
  208.    sleep -m 3000
  209.    Out-Buffer '' 'Gray' 'black'
  210.    Out-Buffer 'Right? '.PadRight(58,"-") 'Red' 'black'  
  211.    Out-Buffer '' 'Gray' 'black'
  212.    sleep -m 600
  213.    Out-Buffer 'It''s clearly not as slick to just pop in multiple lines' 'white' 'black'
  214.    sleep -m 1200
  215.    Out-Buffer 'with absolutely no scroll delay, and it makes it a little ' 'white' 'black'
  216.    sleep -m 1200
  217.    Out-Buffer 'hard to tell what you have read already, but that''s ok.' 'white' 'black'
  218.    sleep -m 1200
  219.    Out-Buffer '' 'Gray' 'black'
  220.    sleep -m 600
  221.    Out-Buffer 'If you delay between paragraphs.' 'Red' 'black'  
  222.    sleep -m 600
  223.    Out-Buffer '' 'Gray' 'black'
  224.    sleep -m 600
  225.    Out-Buffer 'But: don''t scroll off-screen faster than I can read!' 'Yellow' 'black'  
  226.    sleep -m 600
  227.    Out-Buffer '' 'Gray' 'black'
  228. }
  229.  
  230. ## Test-BufferBox 3.0
  231. ####################################################################################################
  232. ## Imagine it's a chat window: you can type, but the whole time, the ongoing conversation in the
  233. ## chat room you have joined is going on in the background.
  234. ##
  235. ## NOTE: because this is a "chat" demo, we treat your input as text, and to execute script in-line
  236. ## you have to enclose it inside $() braces.
  237. ####################################################################################################
  238. function Demo2 {
  239. param( $title = "PowerShell Interactive Buffer Demo" )
  240.  
  241. Reset-Buffer -ShowInput -Title $Title
  242.  
  243. ###################################################################################################
  244. ##### We only need this for the purposes of the demo...
  245. ##### In a real script you would, presumably, be getting stuff from somewhere else to display
  246.    $noise = $MyInvocation.MyCommand.Definition -split "`n"
  247.    $index = 0;
  248.    $random = New-Object "Random"
  249.  
  250. ##### Printing a "How to Exit" message
  251. Out-Buffer "  " -Fore DarkGray -Back Cyan
  252. Out-Buffer "     This is just a demo. " -Fore Black -Back Cyan
  253. Out-Buffer "     We will stream in the source code of this script ... " -Fore Black -Back Cyan
  254. Out-Buffer "     And you can type at the bottom while it's running. " -Fore Black -Back Cyan
  255. Out-Buffer "     Imagine this as an n-way chat application like IRC, except that " -Fore Black -Back Cyan
  256. Out-Buffer "  FOR THIS PERFORMANCE ONLY: " -Fore Black -Back Cyan
  257. Out-Buffer "         The part of your chatting friends is played by my source code. " -Fore DarkGray -Back Cyan
  258. Out-Buffer "  " -Fore DarkGray -Back Cyan
  259. Out-Buffer "     Press ESC to exit, or enter 'exit' and hit Enter" -Fore Black -Back Cyan
  260. Out-Buffer "  " -Fore DarkGray -Back Cyan
  261. ##### Setting the prompt
  262. Set-BufferInputLine
  263. ##### And initializing our two variables ...
  264. $line=""
  265. $exit = $false
  266. while(!$exit){
  267.    while(!$exit -and $Host.UI.RawUI.KeyAvailable) {
  268.       $char = $Host.UI.RawUI.ReadKey("IncludeKeyUp,IncludeKeyDown,NoEcho");
  269.       # we don't want the key up events, but we do want to get rid of them
  270.       if($char.KeyDown) {
  271.       switch([int]$char.Character) {
  272.          13 { # Enter
  273.                if($line.Trim() -eq "exit") { $exit = $true; break; }
  274. ###################################################################################################
  275. ###################################################################################################
  276. ############# WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING #############
  277. ############# This executes the user input!                                           #############
  278. ############# Don't use this on, say, content you got from a web page or chat room    #############
  279.             iex "Out-Buffer `"$line`" -Fore Red";                                     #############
  280. ###################################################################################################
  281. ###################################################################################################
  282.             $line = "";
  283.             Set-BufferInputLine
  284.          }
  285.          27 { # Esc
  286.             $exit = $true; break;
  287.          }
  288.            8 { # Backspace
  289.             if($line.Length -gt 0) {
  290.                $line = $line.SubString(0,$($line.Length-1))
  291.             }
  292.             # $pos = $Host.UI.RawUI.CursorPosition
  293.             Set-BufferInputLine $line
  294.          }
  295.          0 {
  296.             # Not actually a key
  297.             # Out-Buffer $($Char | Out-String)
  298.            
  299.          }
  300.          default {
  301.             $line += $char.Character
  302.             Set-BufferInputLine $line
  303.          }
  304.       }
  305.       }
  306.    }
  307.    # Simulate doing useful things 25% of the time
  308.    if($random.NextDouble() -gt 0.75) {
  309.       $noise[($index)..($index++)] | Out-Buffer
  310.       if($index -ge $noise.Length){$index = 0}
  311.    }
  312.    sleep -milli 100
  313. }
  314. $CursorPosition = $BufferPromptPosition
  315. $CursorPosition.Y += 2
  316. $CursorPosition.X = 0
  317. $Host.UI.RawUI.CursorPosition = $CursorPosition
  318. }

Submit a correction or amendment below (
click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:


Remember me