Skip to content

Commit

Permalink
fix: padding of wide rune
Browse files Browse the repository at this point in the history
  • Loading branch information
xiongnemo committed Mar 14, 2024
1 parent 32dca2d commit dacd32a
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 14 deletions.
Binary file modified Assets/screenshot.cli.2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ If you are on a Windows and [scoop](https://github.com/ScoopInstaller/Scoop)-rea
scoop bucket add nemo https://github.com/xiongnemo/windows-binaries-scoop-bucket && scoop install SonicLair.Cli
```

Use a proper monospace font (with CJK if you want) to correctly show the paddings.

### Linux caveats

For linux, the app will search for the relevant libvlc files from your installation.
Expand Down
2 changes: 2 additions & 0 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ SonicLair.Cli 是一个使用 .NET Core 8 构建的运行在终端里的 Subsoni
scoop bucket add nemo https://github.com/xiongnemo/windows-binaries-scoop-bucket && scoop install SonicLair.Cli
```

使用一个等宽字体(如果你需要的话,CJK)来正确显示终端中的文字排版。

### Linux

对于 Linux,应用程序会自动搜索 libvlc。
Expand Down
34 changes: 34 additions & 0 deletions SonicLair.Cli/Tools/StringExtension.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
namespace SonicLair.Cli.Tools
{
public static class StringExtension
{
public static int StandardizedStringLength(this string input)
{
// each CJK rune is 2 letter width when using a monospaced font
int length = 0;
foreach (var c in input)
{
length += Rune.IsWideChar(c) ? 2 : 1;
}
return length;
}
public static string RunePadRight(this string stringToPad, int totalWidth, char paddingChar = ' ')
{
int standardizedStringLength = stringToPad.StandardizedStringLength();
if (standardizedStringLength >= totalWidth)
{
return stringToPad;
}
return stringToPad.PadRight(totalWidth - (standardizedStringLength - stringToPad.Length), paddingChar);
}
public static string RunePadLeft(this string stringToPad, int totalWidth, char paddingChar = ' ')
{
int standardizedStringLength = stringToPad.StandardizedStringLength();
if (standardizedStringLength >= totalWidth)
{
return stringToPad;
}
return stringToPad.PadLeft(totalWidth - (standardizedStringLength - stringToPad.Length), paddingChar);
}
}
}
28 changes: 14 additions & 14 deletions SonicLair.Cli/Windows/MainWindow.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
using LibVLCSharp.Shared;
using Microsoft.VisualBasic;
using NStack;

using SonicLair.Cli;
using SonicLair.Cli.Tools;
using SonicLair.Lib.Infrastructure;
using SonicLair.Lib.Services;
using SonicLair.Lib.Types.SonicLair;
Expand Down Expand Up @@ -245,9 +245,9 @@ private void SearchView()
{
X = 0,
Y = 0,
Width = 9,
Width = 11,
Height = 1,
Text = "[Search:]",
Text = "[Search: ?]",
CanFocus = false,
};
TextField searchField = SonicLairControls.GetTextField("");
Expand Down Expand Up @@ -330,14 +330,14 @@ private void SearchView()
}
var cancellationTokenSource = new CancellationTokenSource();
SonicLairControls.AnimateTextView(searchLabel, new[]{
"[Search/]",
"[Search-]",
"[Search\\]",
"[Search|]",
"[Search: /]",
"[Search: -]",
"[Search: \\]",
"[Search: |]",
}, 800, cancellationTokenSource.Token);
var ret = await _subsonicService!.Search(value.ToString(), 100);
cancellationTokenSource.Cancel();
searchLabel.Text = "[Search:]";
searchLabel.Text = "[Search: ?]";
Application.MainLoop.Invoke((Action)(() =>
{
if (ret.Artists != null && ret.Artists.Any<Artist>())
Expand All @@ -352,15 +352,15 @@ private void SearchView()
var max = ret.Albums.Max(s => s.Name.Length);
albumsList.Source = new SonicLairDataSource<Album>(ret.Albums, (s) =>
{
return $"{s.Artist} :: {s.Name.PadRight(max, ' ')}";
return $"{s.Artist} :: {s.Name.RunePadRight(max, ' ')}";
});
}
if (ret.Songs != null && ret.Songs.Any<Song>())
{
var max = ret.Songs.Max(s => s.Title.Length);
songsList.Source = new SonicLairDataSource<Song>(ret.Songs, (s) =>
{
return $"{s.Artist} :: {s.Album} :: {s.Title.PadRight(max, ' ')}";
return $"{s.Artist} :: {s.Album} :: {s.Title.RunePadRight(max, ' ')}";
});
}
Application.Refresh();
Expand Down Expand Up @@ -417,7 +417,7 @@ private async Task ArtistsView()
listView.Source = new SonicLairDataSource<Artist>(artists, (a) =>
{
var tag = a.AlbumCount > 1 ? "Albums" : "Album";
return $"{a.ToString().PadRight(max, ' ')} {a.AlbumCount.ToString().PadLeft(maxAlbums, ' ')} {tag}";
return $"{a.ToString().RunePadRight(max, ' ')} {a.AlbumCount.ToString().RunePadLeft(maxAlbums, ' ')} {tag}";
});
listView.OpenSelectedItem += ArtistsView_Selected;
mainView.Add(listView);
Expand Down Expand Up @@ -491,7 +491,7 @@ private async Task PlaylistView(string id)
var maxArtist = playlist.Entry.Max(s => s.Artist.Length);
var source = new SonicLairDataSource<Song>(playlist.Entry, (s) =>
{
return $"{s.Title.PadRight(maxTitle, ' ')} :: {s.Artist.PadRight(maxArtist, ' ')} [{s.Duration.GetAsMMSS()}]";
return $"{s.Title.RunePadRight(maxTitle, ' ')} :: {s.Artist.RunePadRight(maxArtist, ' ')} [{s.Duration.GetAsMMSS()}]";
});
listView.Source = source;
listView.OpenSelectedItem += (ListViewItemEventArgs e) =>
Expand Down Expand Up @@ -523,7 +523,7 @@ private async Task PlaylistsView()
var maxOwner = playlists.Max(s => s.Owner.Length);
listView.Source = new SonicLairDataSource<Playlist>(playlists, (p) =>
{
return $"{p.Name.PadRight(maxName + 1, ' ')} :: {p.Owner.PadRight(maxOwner + 1, ' ')} [lasts {p.Duration.GetAsMMSS()}]";
return $"{p.Name.RunePadRight(maxName + 1, ' ')} :: {p.Owner.RunePadRight(maxOwner + 1, ' ')} [lasts {p.Duration.GetAsMMSS()}]";
});
listView.OpenSelectedItem += (ListViewItemEventArgs e) =>
{
Expand Down Expand Up @@ -585,7 +585,7 @@ private void CurrentStateHandler(object? sender, CurrentStateChangedEventArgs e)
}
else
{
title = s.Title.PadRight(max, ' ');
title = s.Title.RunePadRight(max, ' ');
}
return $"{(s.Id == currentId ? "*" : "")}{title}[{s.Duration.GetAsMMSS()}]";
});
Expand Down

0 comments on commit dacd32a

Please sign in to comment.