Autogenerating terminal window screenshots from text/commands for documentation? - macos

Ok, I hope that stackoverflow is the right place to ask this: I've searched high and wide and haven't come up with a good solution so far.
I'm writing a bunch of documentation for command-line and programming newbies, including nice screenshots of what they might see as they interact with a terminal window. I am thinking of doing this in something like restructuredtext so that I can keep it version controlled and multiformat (for later conversion to html, latex/pdf, etc). Is there any way that I can keep the commands/code/text/etc in a document for revision control, and yet still produce nice user-friendly screenshots in an automated way for inclusion in the final doc? Just as an example, perhaps in in my markup I had something like this (I'm not very familiar with restructuredtext directives yet, but they seem pretty powerful):
.. terminal:: ls_example.png
pre:
/Users/soneil/Documents/test% ls
post:
/Users/soneil/Documents/test% ls
testfile todo.txt
/Users/soneil/Documents/test%
and get two screenshots of terminal windows with the appropriate text in them. The trickier part would be ansi characters for things like editors:
.. terminal:: nano_example.png
pre:
/Users/soneil/Documents/test% ls
testfile todo.txt
/Users/soneil/Documents/test% nano todo.txt
post:
(Either the contents of test.txt right here [with or without editor decoration as well,
which could be faked if needed],
or let a script actually run the command and capture the output somehow)
Resulting in something like:
Pre: http://d.pr/i/a1JS
Post: http://d.pr/i/Edu4
(Sorry for the links, I guess I don't have enough reputation for images yet, nor do I have enough reputation to post more than two links).
I'm working on OSX now, but I'm not tied to the Terminal app (or even OSX, really). If I could specify the cols/rows of the windows as well that would be nice. Creative solutions involving programming, imagemagick, ttyrec, etc. welcome; I've even considered applescript interaction with Terminal.app but with minimal success. I am hoping to get something out the other end with ansi colors (e.g. views of top, htop) and preferably window chrome, so a raster format like png seems logical so far.
Whew! Thanks for your time-

Your idea of automatically generating screenshots is great, but if you actually do them as image files, it won’t be so great because people won’t be able to copy-and-paste from them.
What I’d suggest instead is to using AppleScript with the copy-as-formatted text feature in the Mavericks terminal to make rich-text copies of the terminal display, and convert that to HTML for including in your documents.
Here’s a ruby script:
#!/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/ruby
command = '/bin/ls -G /'
clipboard = `osascript -e '
tell application "Terminal"
set newTab to do script
delay 0.1
do script "#{command}" in newTab
delay 0.1
activate newTab
-- ⌘-A select all
tell application "System Events" to keystroke "a" using command down
-- ⌘-C copy
tell application "System Events" to keystroke "c" using command down
delay 0.1
do script "exit" in newTab
end tell
get the clipboard as «class RTF »
'`
# this returns "«data RTF 7B5C…27D»"; need to strip out the hex data
hex_data = /[A-F0-9]{2,}/.match(clipboard).to_s
data = [hex_data].pack('H*')
converter = IO.popen('textutil -cat html -stdin -stdout', 'w+')
converter.puts data
converter.close_write
puts converter.gets(sep='')
It sends command to the terminal, copies the terminal contents, grabs the terminal contents from the clipboard, and converts it to HTML.
If you plop the output of that straight into a browser
you get a copy of your terminal, with fonts and colours preserved, all copy-and-pastable:
The output HTML can be a bit messy, but since it’s already data inside Ruby you can write code to clean it up. And if you still want the terminal frame around the terminal output, you can do that with CSS.
Hope this helps!

Related

How do programs like man, screen, and vim create temporary overlays?

Several *NIX commands, such as screen, man, vim and others, create a temporary canvas/screen/overlay in a shell environment. When such programs execute, they cover or hide whatever content was displayed in the terminal before — almost like a "full screen" mode, within the terminal window. When they terminate, however, they reveal or restore whatever had been on the terminal before.
In the example below, I create some filler text on the screen, then invoke man bash. The man page opens up and covers all other characters on the terminal display. When I close the man page, the characters that had been covered up are again shown.
Before
While an example full-screen program is running
After
I would expect that programs writing to stdout/stderr could accomplish the first step (replacing the content of the terminal with program-specific content), but then it would produce a ton of text that I could scroll through, and therefore couldn't do the second step: restoring the contents of the terminal. That means that somehow either the program memorizes the previous contents of the screen and re-outputs them (I doubt it?), or it creates some sort of sub-window within a terminal and something else keeps track of the previous contents of the terminal.
My Question
How can I accomplish that behavior in my own program and/or script?
Perhaps I should use curses/ncurses, tput, termcap/terminfo, or ANSI escape sequences?
Update:
This revised question is essentially the same as https://unix.stackexchange.com/questions/27941/show-output-on-another-screen-and-return-to-normal-when-done. (I hadn't found it when I had written this question despite lots of searching.) The difference is that my question is more general (any language) whereas that question is specific to Bash. The answers to both questions are essentially the same. If it's too similar to a question on another site, feel free to close it here for that reason.
How do these programs accomplish that behavior?
ANSI escape sequences. Try running this script:
#/bin/bash -
tput smcup
echo 'Hello world!'
sleep 3
tput rmcup
Using infocmp, you can see underlying sequences that create this overlaying effect, e.g:
$ infocmp -1 | grep 'rmcup\|smcup'
rmcup=\E[?1049l\E[23;0;0t,
smcup=\E[?1049h\E[22;0;0t,
is this behavior shell-dependent or system-dependent?
None, it depends on whether the terminal emulator supports save/restore operations.

Run AppleScript progress bar in separate window from command line?

To display dialogs from the command line I just use
$ osascript File.scpt
However, the progress bar feature isn't constrained to a dialog window because it adapts to the current application, e.g. a Finder window, where the progress updates are shown on the bottom of the window. File.scpt would look something like this.
set numUpdates to 100
set progress total steps to numUpdates
set progress completed steps to 0
set progress description to "Updating..."
set progress additional description to "Preparing to process."
set cycle to 1
repeat with a from 1 to numUpdates
# update description, completed steps, etc
end repeat
When I run my script from a terminal window, however, the script runs but nothing is shown to indicate the progress. Is there a way to force the progress bar to open as a new dialog or something along those lines without having to export the script as a ".app" file?
The reason Script Editor can display progress in its window and Terminal cannot is because Script Editor has its own extended scripting definition with the extra functions so when the script is run via script editor it has been programmed with the extra progress indicator but no other applications are sorry. The way I see it, you pretty much have 2 ways I can think of that will let you display "Progress" in AppleScript:
This is kinda ugly but I used to just have a transparent spinner gif file that will be displayed in a dialog which will give the affect that something is loading or working. and a single button saying Nothing or OK eg.
display dialog "Loading..." buttons:{"OK"} with icon ("/path/to/loader.gif" as POSIX file)
And if you wanna make it temporary just add giving up after (duration in seconds)
This is probably the best option but it is probably more complicated. I advise that you transfer to a programming language called "AppleScript Objective C" otherwise known as "Cocoa AppleScript". This allows you to use the basic AppleScript commands with Cocoa Windows/Dialogs/etc including progress bars!. to start you off you should download Xcode and research AppleScript Objective C and perhaps stick to it. Its better than AppleScript but still has the same functions :)

How to use vim in the terminal?

How does one setup and start using vim in the terminal on OS X?
I want to start writing my C code using vim in the terminal rather than a separate text editor. How does one get started on this?
The basics like: opening, creating, saving files via terminal using vim and writing code using vim. Also, does one compile directly using vim in the terminal?
Get started quickly
You simply type vim into the terminal to open it and start a new file.
You can pass a filename as an option and it will open that file, e.g. vim main.c. You can open multiple files by passing multiple file arguments.
Vim has different modes, unlike most editors you have probably used. You begin in NORMAL mode, which is where you will spend most of your time once you become familiar with vim.
To return to NORMAL mode after changing to a different mode, press Esc. It's a good idea to map your Caps Lock key to Esc, as it's closer and nobody really uses the Caps Lock key.
The first mode to try is INSERT mode, which is entered with a for append after cursor, or i for insert before cursor.
To enter VISUAL mode, where you can select text, use v. There are many other variants of this mode, which you will discover as you learn more about vim.
To save your file, ensure you're in NORMAL mode and then enter the command :w. When you press :, you will see your command appear in the bottom status bar. To save and exit, use :x. To quit without saving, use :q. If you had made a change you wanted to discard, use :q!.
Configure vim to your liking
You can edit your ~/.vimrc file to configure vim to your liking. It's best to look at a few first (here's mine) and then decide which options suits your style.
This is how mine looks:
To get the file explorer on the left, use NERDTree. For the status bar, use vim-airline. Finally, the color scheme is solarized.
Further learning
You can use man vim for some help inside the terminal. Alternatively, run vimtutor which is a good hands-on starting point.
It's a good idea to print out a Vim Cheatsheet and keep it in front of you while you're learning vim.
Run vim from the terminal. For the basics, you're advised to run the command vimtutor.
# On your terminal command line:
$ vim
If you have a specific file to edit, pass it as an argument.
$ vim yourfile.cpp
Likewise, launch the tutorial
$ vimtutor
You can definetely build your code from Vim, that's what the :make command does.
However, you need to go through the basics first : type vimtutor in your terminal and follow the instructions to the end.
After you have completed it a few times, open an existing (non-important) text file and try out all the things you learned from vimtutor: entering/leaving insert mode, undoing changes, quitting/saving, yanking/putting, moving and so on.
For a while you won't be productive at all with Vim and will probably be tempted to go back to your previous IDE/editor. Do that, but keep up with Vim a little bit every day. You'll probably be stopped by very weird and unexpected things but it will happen less and less.
In a few months you'll find yourself hitting o, v and i all the time in every textfield everywhere.
Have fun!
if you want to open all your .cpp files with one command, and have the window split in as many tiles as opened files, you can use:
vim -o $(find name ".cpp")
if you want to include a template in the place you are, you can use:
:r ~/myHeaderTemplate
will import the file "myHeaderTemplate in the place the cursor was before starting the command.
you can conversely select visually some code and save it to a file
select visually,
add w ~/myPartialfile.txt
when you select visualy, after type ":" in order to enter a command, you'll see "'<,'>" appear after the ":"
'<,'>w ~/myfile $
^ if you add "~/myfile" to the command, the selected part of the file will be saved to myfile.
if you're editing a file an want to copy it :
:saveas newFileWithNewName
If you want to learn by reading yourself:
Open MacOS terminal app.
Write this and press enter -> vimtutor
For quit write this and click -> :q

AppleScript to take text and turn it into pasteable HTML

We work with bugzilla. Whenever you need to query a ticket you just need to know the bugid (integer) and you simply prepend this to it.
http://<bugzilla_server>/bugzilla/show_bug.cgi?id=<bug_id>
Suppose I have a bug link which looks like this 777. If I select and copy this it is preserved on the pasteboard so when I paste this into mail it will correctly preserve the link and it's attributes.
What I am looking for is to simple type '777' select it and run an applescript on it and replace it with a link like the one above. Can anyone help me out??
The following AppleScript will take the contents of the clipboard and replace it with the URL prepended:
set the clipboard to "http://bugzilla_server/bugzilla/show_bug.cgi?id=" & (the clipboard)
You can compile that to an AppleScript scpt and make it available in a Scripts folder or compile it to a launchable app:
osacompile -e 'set the clipboard to "http://bugzilla_server/bugzilla/show_bug.cgi?id=" & (the clipboard)' -o replacebug.scpt # or -o replacebug.app
If your primary use case for this is in composing mail in Mail.app, this may not be the most user-friendly approach, though. If you are using Snow Leopard (10.6), a simpler solution is to take advantage of the new Text Substitution feature. Open the System Preferences -> Language & Text preference panel, select the Text tab, and click + to add a new substitution, perhaps:
Replace With
(b) http://bugzilla_server/bugzilla/show_bug.cgi?id=
Then, in Mail.app, start a New Message and, with the cursor clicked within the text body, do a Control click of the mouse to bring up the contextual menu. From it, select Substitutions -> Text Replacement. From now on, as you are typing in the text body of the email when you type:
(b)777
the (b) will automatically change to the URL text you saved:
http://bugzilla_server/bugzilla/show_bug.cgi?id=777
This will also work in other Cocoa text-enabled applications like Safari.
EDIT:
When talking about composing URL links in email, there are at least three different formats of email, each with a different solution. Since you don't say which kind you are using, I'll cover all three:
Plain text format - There's no way to "hide" the URL in the composed email although some email readers might present a clickable link for a plain-text URL.
HTML-formatted email - Apple's Mail.app does not support composing email in this format although it will display it. Using some other mail writer client or your own program, it's easy enough to compose a link using a standard HTML anchor <a href=...> tag.
Rich Text Format email - AFAIK, this is the only way to compose a URL link with Mail.app. Unfortunately, there does not appear to be an easy way to directly create an RTF hyperlink using AppleScript commands. Based on a suggestion here, this is a way to do it by creating a modifiable RTF template via the clipboard.
In TextEdit.app, create a new Document window.
Insert the text you want to appear in the email, i.e. 777.
Select the text (⌘A) then add a link (⌘K). Enter the full URL also with 777 into the "Link destination" field; click OK.
Modify the text format as desired with Format menu commands.
Save the file (⇧⌘S) as temp.rtf with File Format -> Rich Text Format.
Close the document window.
Open a document window (⌘O) selecting file temp.rtf and selecting Ignore rich text commands.
Insert the following before the first line in the file:
#!/bin/sh
sed -e "s/777/$(pbpaste -Prefer txt)/g" <<EOF | pbcopy -Prefer rtf
Append EOF as a separate line at the end of the file.
It should now look something like this:
#!/bin/sh
sed -e "s/777/$(pbpaste -Prefer txt)/g" <<EOF | pbcopy -Prefer rtf
{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf250
{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
{\colortbl;\red255\green255\blue255;}
\margl1440\margr1440\vieww9000\viewh8400\viewkind0
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
{\field{\*\fldinst{HYPERLINK "http://bugzilla_server/bugzilla/show_bug.cgi?id=777"}}{\fldrslt
\f0\fs24 \cf0 777}}}
EOF
Save this as a Plain Text file and execute directly as a shell script or call it via the AppleScript do shell script command.
This kind of solution will work with most other applications that support Rich Text format.
Not sure exactly the function you're looking for, but this will take a number from your clipboard and process it into a link and put the link on the clipboard as a standard href URL that will work in plain or rich text, like:
Bug number 777 link
Change <bugzilla_server> to your working URL.
set bug_number to the clipboard
set the_text to "Bug number " & bug_number & " link"
set the clipboard to the_text

Manipulating text in XCode, moving one line

In emacs I have various functions to manipulate text. Now that I'm using xcode, I suppose I could make emacs my default editor, but I want to browse obj-c objects and such, so I'd rather just implement my most used text manipulation commands for xcode.
First on my list, I'd like a command that moves the text of the current line up/down one line, keeping the cursor on the current line.
In emacs this is:
(defun move-one-line-downward ()
"Move current line downward once."
(interactive)
(forward-line)
(transpose-lines 1)
(forward-line -1))
I'd be happiest if I could write a script in Python that would do the equivalent in XCode, but as far as I can tell, I need to talk to AppleScript to do this.
Can someone walk me through how to do this with XCode?
Xcode 4 has a new set of command for moving the line where the cursor is or the selected text with command + option + [ or ]
⌥⌘[ or ⌥⌘]
http://developer.apple.com/library/mac/#documentation/IDEs/Conceptual/xcode_help-command_shortcuts/MenuCommands/MenuCommands014.html
What you’re wanting to do can be achieved through Xcode’s “User Scripts”—and it helpfully comes with a pair of scripts that almost do what you want. (I’m using Xcode 3.2 here, but I think these were also there in 3.1)
Look in /Developer/Library/Xcode/User Scripts/; there are two applescripts there, Move Line Up.scpt and Move Line Down.scpt. Here’s what’s in Move Line Up:
(*
To edit this script, choose Save As... and save it in your home directory, then re-add it to the User Scripts list.
*)
using terms from application "Xcode"
tell first text document
set {startLine, endLine} to selected paragraph range
if startLine > 1 then
set theText to (paragraphs startLine through endLine)
set theText to (theText as string)
delete (paragraphs startLine through endLine)
make new paragraph at beginning of paragraph (startLine - 1) with data theText
set selected paragraph range to {startLine - 1, endLine - 1}
else
beep 1
end if
end tell
end using terms from
These almost do what you want, except they select the whole line afterwards; I’m no applescript expert, but you probably want to store the selected character range. Have a look at the Xcode scripting dictionary (in AppleScript Editor, File -> Open Dictionary -> Xcode) to find out the types of objects you can manipulate.
You can add your own scripts to Xcode with the “Edit User Scripts”menu item in the script menu; and assign shortcut keys to the scripts in that window also, by double-clicking in the right-hand column beside the entry for the script menu item.
You can also use shell scripts (perl, python, bash, whatever) in the User Scripts menu, but these process only the selection or the whole file, so might be a bit heavyweight for moving a single line up or down.
See all the docuemntation on User Scripts here: http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/XcodeWorkspace/310-User_Scrips/user_scripts.html
I hope this helps!
I think your question is more generic that Xcode/emacs. Most IDE can't do stuff that editors can do and vice versa.
What I do is to use Xcode for 'simple' stuff and compile/debug. When I want to do lot's of coding (hm ... text editing) I open multiple files in one Vim (no offense to emacs ... vim is my editor of choice) and use all the vim tricks available.
I follow the same process when I need to do lots of coding on Windows (Visual Studio). I have VS opened just for compiling/debugging but I do most coding in separate Vim window.
I don't need to do any of that on Unix because I just open file in Vim and run Makefile from within Vim, jumping directly to errors and so on (:mak) ...
I'm sure that there are some extremely clever things to get Xcode do stuff that are already in Vim and Vim to do stuff that Xcode can do but I'm focusing on coding so not much time to play around.
Also, you can hook up emacs (or vi, or bbedit, or ed, I imagine) to xcode, so that they will talk to each other. When you tell xcode to open a file it will call emacsclient, etc. You can even get emacs to tell xcode where to put a breakpoint (I don't remember how, but I asked a question here a while back, and it works great)

Resources