I recently did a post on
customizing the sbt command line prompt see http://www.whiteboardcoder.com/2016/03/sbt-customize-shell-prompt-in-sbt.html [1]
Now I want to tweak my
code a bit to list the current git branch I am on.
I was inspired by this
github project that uses powerline fonts. https://github.com/agemooij/sbt-prompt [2]
This project has some
pretty good results and even has a nice glyph for branch.
For me, though, I want
to make my own setup so I can tweak it as my needs change.
Git branch
To get just the current
branch name in git you can run this command.
> git
rev-parse --abbrev-ref HEAD
|
Now I just need to
incorporate that into my ~/.sbt/0.13/global.sbt file
> vi
~/.sbt/0.13/global.sbt
|
Here is my updated code
shellPrompt := { state =>
def textColor(color:
Int) = {
s"\033[38;5;${color}m" }
def
backgroundColor(color:Int) = { s"\033[48;5;${color}m" }
def reset = {
s"\033[0m" }
def gitBranch =
Process("git rev-parse --abbrev-ref HEAD").lines.head
def formatText(str:
String)(txtColor: Int, backColor: Int) = {
s"${textColor(txtColor)}${backgroundColor(backColor)}${str}${reset}"
}
val red = 1
val green = 2
val yellow = 11
val white = 15
val black = 16
val orange = 166
formatText(s"[${name.value}]")(white, orange) +
formatText(s" $gitBranch
")(black, yellow) +
"\n " +
formatText("\u276f")(orange, black) +
formatText("\u276f")(orange, black) +
formatText("\u276f
")(orange, black)
}
|
And here are the results.
When I reload sbt it grabs the correct branch I am currently
on.
The only thing I would want to add to this is a branch glyph
like this
I imagine the best way to do that is to find a Unicode glyph
close to that and use FontForge to tweak my current Font I use.
I have used FontForge in the past to tweak my current Font
and I have some note on it http://www.whiteboardcoder.com/2015/02/fontforge.html
[3] I also have a short video I made on the subject https://www.youtube.com/watch?v=eDPC1e546wg
[4]
Find the Unicode Character
First let me find the Unicode Character that is closes to
the branch symbol.
One tool you can use to try and find Unicode fonts is http://shapecatcher.com/ [5]
Go there draw something and click Recognize
After a few tries I really did not get what I wanted. But still it’s a pretty cool tool.
Poking around I found a few possibles.
Unicode
|
Symbol
|
\u2387
|
|
\uE0A0
|
|
OK why the E0A0?
I opened one of the fonts in FontForge to see
That is the one that Powerline uses. It is also in the Supplementary Special
Purpose Plan of Unicode see https://en.wikipedia.org/wiki/Plane_(Unicode)#Supplementary_Special-purpose_Plane
[6]
I am not really sure what that means, is it just an unused
section of Unicode?
At any rate I think it best to use the same Unicode
character the powerline folks are using.
Updating my code
If I update my code
shellPrompt := { state =>
def textColor(color:
Int) = {
s"\033[38;5;${color}m" }
def backgroundColor(color:Int)
= { s"\033[48;5;${color}m" }
def reset = {
s"\033[0m" }
def gitBranch = "\uE0A0 " + Process("git rev-parse --abbrev-ref
HEAD").lines.head
def formatText(str:
String)(txtColor: Int, backColor: Int) = {
s"${textColor(txtColor)}${backgroundColor(backColor)}${str}${reset}"
}
val red = 1
val green = 2
val yellow = 11
val white = 15
val black = 16
val orange = 166
formatText(s"[${name.value}]")(white, orange) +
formatText(s"$gitBranch
")(black, yellow) +
"\n " +
formatText("\u276f")(orange, black) +
formatText("\u276f")(orange, black) +
formatText("\u276f
")(orange, black)
}
|
I get nothing since my font is not have this glyph.
I am going to fix that with Font-Forge by simply copying
down the powerline fonts and use Font-Forge to copy and paste a few glyphs.
Run this command to download the powerfonts from github
> git clone
https://github.com/powerline/fonts.git
|
I would suggest using one of the downloaded powerline fonts,
if you can get it to work for you.
Please do it! The rest of this
article is me fighting with FontForge/Windows/Cygwin to try and get what I want
working…
Fight the good Font fight
OK after a lot of fighting with my own font here is the
procedure I came up with the fix my own setup (windows 7 + Cygwin)
First of all Cygwin is finicky with the fonts it will can
use. They need to be monospaced and all
glyphs must have the same set width.
Here is my procedure
1. Shut down Cygwin
2. Remove all Sans Typewriter fonts from C:\Windows\Fonts
3. Download a new copy of Lucida Sans Typewriter from http://www.myfontfree.com/download-lucida-sans-typewriter-zip37263.htm (mostly because I just need a nice fresh one to alter)
4. Open the download Font in FontForge and also Open one of the Powerline Fonts. (also in my case open the prior Font I had tweaked)
5. Copy over my own personal odd Unicode Glyph to the new font.
Click on View then GoTo
Enter U+276f and click OK
Right click on the Glyph and select
Copy.
Then paste over in the same Unicode Glyph in the new font.
Now copy these Glyphs over to the
new font
Copy them to the same location
Select Edit à Select Ã
Glyphs Worth Outputing.
This should select all the Glyphs that matter.
Select Metrics and click Set Width
Set width to 1234 and click OK
8. Make sure it is monospaced
Click on element and Font Info.
Select OS/2 and click on Panose
Select Monospaced for Proportion and click OK.
9. Make the font
Select File and click Generate Fonts
Save to the Desktop and click Generate
You may get an error like this click Generate.
10. Copy Font to C:\Windows\Fonts
11. Open Cygwin and change font to the new updated font.
11. Open Cygwin and change font to the new updated font.
(note: I was doing so
many tests at one point I just had to reboot my machine as it had messed with
my Fonts too much).
Test
You can test to see if a Unicode character will work by
running this command.
> echo
-e '\u276f'
|
Hey it worked!
For some reason the E0xx range does not work on the command
line (thought it does actually work in sbt just fine for some reason)
Back to tweaking my sbt
shellPrompt := { state =>
//Special Characters
val branch = "\uE0A0"
val lock
= "\uE0A2"
val rArrow = "\uE0B0"
val lArrow = "\uE0B2"
def textColor(color:
Int) = {
s"\033[38;5;${color}m" }
def backgroundColor(color:Int)
= { s"\033[48;5;${color}m" }
def reset = {
s"\033[0m" }
def gitBranch = s" $branch
${Process("git rev-parse --abbrev-ref HEAD").lines.head}"
def formatText(str:
String)(txtColor: Int, backColor: Int) = {
s"${textColor(txtColor)}${backgroundColor(backColor)}${str}${reset}"
}
val red = 1
val green = 2
val yellow = 11
val white = 15
val black = 16
val orange = 166
formatText(s"[${name.value}]")(white, orange) +
formatText(s"$gitBranch ")(black, yellow) +
"\n " +
formatText("\u276f")(orange, black) +
formatText("\u276f")(orange, black) +
formatText("\u276f
")(orange, black)
}
|
Here are the results.
There is a bug though… If there is not git repo in the directory it crashes. Let me fix that.
Process Builder
Poking around I found
Process Builder http://www.scala-lang.org/api/2.11.7/#scala.sys.process.ProcessBuilder
[8]
I have never fiddled with Process builder so whatever I make
here my be a little hacky… so bear with me.
I found a good example how to use it at http://stackoverflow.com/questions/15411728/scala-process-capture-standard-out-and-exit-code
[9] the post from Rogach
def runCommand(cmd: Seq[String]): (Int, String, String) = {
val stdout = new
ByteArrayOutputStream
val stderr = new
ByteArrayOutputStream
val stdoutWriter = new
PrintWriter(stdout)
val stderrWriter = new
PrintWriter(stderr)
val exitValue = cmd.!(ProcessLogger(stdoutWriter.println,
stderrWriter.println))
stdoutWriter.close()
stderrWriter.close()
(exitValue,
stdout.toString, stderr.toString)
}
|
Copying this code over to my sbt file does not seem to work
for me. I am getting some
conflicts. I think it wants to use the
sbt.ProcessBuilder vs the Scala.sys.process.ProcessBuilder.
Here are a few resources I found while fighting with this.
(this had an empty ProcessLogger)
(this seems to be the code which I cannot seem to find on
github… but I know sbt is going through a lot of changes at the moment… anyway
lots to learn)
(External Process)
At any rate here is what I came up with.
import java.io.{ByteArrayOutputStream, PrintWriter}
import sbt.{ProcessBuilder, ProcessLogger}
def runCommand(cmd:
Seq[String]): (Int, String, String) = {
val stdout = new
ByteArrayOutputStream
val stderr = new
ByteArrayOutputStream
val stdoutWriter = new
PrintWriter(stdout)
val stderrWriter = new
PrintWriter(stderr)
val exitValue =
cmd.!(new ProcessLogger {
def info (s: =>
String) { stdoutWriter.print(s) }
def error (s: =>
String) { stderrWriter.print(s) }
def buffer[T] (f:
=> T): T = f
})
stdoutWriter.close()
stderrWriter.close()
(exitValue,
stdout.toString, stderr.toString)
}
def gitBranch
= {
runCommand("git
rev-parse --abbrev-ref HEAD".split(" ").toSeq) match {
case (exit, _, _) if(exit != 0) => "No-Git"
case (_, stdout, _) => stdout
}
}
shellPrompt := { state =>
//Special Characters
val branch =
"\uE0A0"
val lock = "\uE0A2"
val rArrow =
"\uE0B0"
val lArrow =
"\uE0B2"
def textColor(color:
Int) = { s"\033[38;5;${color}m"
}
def
backgroundColor(color:Int) = { s"\033[48;5;${color}m" }
def reset = {
s"\033[0m" }
def formatText(str:
String)(txtColor: Int, backColor: Int) = {
s"${textColor(txtColor)}${backgroundColor(backColor)}${str}${reset}"
}
val red = 1
val green = 2
val yellow = 11
val white = 15
val black = 16
val orange = 166
formatText(s"[${name.value}]")(white, orange) +
formatText(s"
$branch $gitBranch ")(black, yellow) +
"\n " +
formatText("\u276f")(orange,
black) +
formatText("\u276f")(orange, black) +
formatText("\u276f
")(orange, black)
}
|
And here are the results if I have a git repo.
In this case called test-branch.
PowerLine like?
I updated my font with the power line symbols and I wonder
if I can use them to get the nice angles.
Here is my code that does that.
import java.io.{ByteArrayOutputStream, PrintWriter}
import sbt.{ProcessBuilder, ProcessLogger}
def runCommand(cmd: Seq[String]): (Int, String, String) = {
val stdout = new
ByteArrayOutputStream
val stderr = new
ByteArrayOutputStream
val stdoutWriter = new
PrintWriter(stdout)
val stderrWriter = new
PrintWriter(stderr)
val exitValue =
cmd.!(new ProcessLogger {
def info (s: =>
String) { stdoutWriter.print(s) }
def error (s: =>
String) { stderrWriter.print(s) }
def buffer[T] (f:
=> T): T = f
})
stdoutWriter.close()
stderrWriter.close()
(exitValue,
stdout.toString, stderr.toString)
}
def gitBranch = {
runCommand("git
rev-parse --abbrev-ref HEAD".split(" ").toSeq) match {
case (exit, _, _) if(exit != 0) => "No-Git"
case (_, stdout,
_) => stdout
}
}
shellPrompt := { state =>
//Special Characters
val branch =
"\uE0A0"
val lock = "\uE0A2"
val rArrow =
"\uE0B0"
val lArrow =
"\uE0B2"
def textColor(color:
Int) = {
s"\033[38;5;${color}m" }
def
backgroundColor(color:Int) = { s"\033[48;5;${color}m" }
def reset = { s"\033[0m"
}
def formatText(str:
String)(txtColor: Int, backColor: Int) = {
s"${textColor(txtColor)}${backgroundColor(backColor)}${str}${reset}"
}
val red = 1
val green = 2
val yellow = 11
val white = 15
val black = 16
val orange = 166
formatText(s"[${name.value}]")(white, orange) +
formatText(rArrow)(orange, yellow) +
formatText(s"
$branch $gitBranch ")(black, yellow) +
formatText(rArrow)(yellow, black) +
"\n " +
formatText("\u276f")(orange, black) +
formatText("\u276f")(orange,
black) +
formatText("\u276f
")(orange, black)
}
|
Hey it worked cool!
I also put this code up as a gist on github at https://gist.github.com/patmandenver/71839aaf63c71f4d6cd2
References
[1] sbt: customize the shell
prompt in sbt
Accessed 03/2016
[2] github stb prompt
Accessed 03/2016
[3] FontForge
Accessed 03/2016
[4] Video: FontForge and Cygwin
Accessed 03/2016
[5] Shapecatcher
Accessed 03/2016
[6] Unicode Special-Purpose
Plane
Accessed 03/2016
[7] Finding common font problems
automagically
Accessed 03/2016
[8] Scala Process Builder
Accessed 03/2016
[9] Scala Process - Capture
Standard Out and Exit Code
Accessed 03/2016
[10] Empty ProcesLogger Example
Accessed 03/2016
[11] Scala Process Builder
Accessed 03/2016
[12] External Process
Accessed 03/2016
No comments:
Post a Comment