pkgman search: Add -D/--details
* Add a detailed listing mode (-D/--details), which prints a table with repository/installation location name, package name, package version, package architecture. * Make the normal listing more compact. Now there's only one row per package. The "Installed" column has been replaced by "Status" which displays if/where the package is installed and whether it matches the repository version.
This commit is contained in:
@@ -17,6 +17,7 @@ BinCommand pkgman :
|
|||||||
JobStateListener.cpp
|
JobStateListener.cpp
|
||||||
PackageManager.cpp
|
PackageManager.cpp
|
||||||
pkgman.cpp
|
pkgman.cpp
|
||||||
|
TextTable.cpp
|
||||||
:
|
:
|
||||||
package be
|
package be
|
||||||
$(TARGET_LIBSUPC++) $(TARGET_LIBSTDC++)
|
$(TARGET_LIBSUPC++) $(TARGET_LIBSTDC++)
|
||||||
|
|||||||
@@ -0,0 +1,274 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "TextTable.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - Column
|
||||||
|
|
||||||
|
|
||||||
|
struct TextTable::Column {
|
||||||
|
Column(const BString& title, enum alignment align, bool canTruncate)
|
||||||
|
:
|
||||||
|
fTitle(title),
|
||||||
|
fAlignment(align),
|
||||||
|
fCanBeTruncated(canTruncate),
|
||||||
|
fNeededWidth(0),
|
||||||
|
fWidth(0)
|
||||||
|
{
|
||||||
|
UpdateNeededWidth(fTitle);
|
||||||
|
fMinWidth = fNeededWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
const BString& Title() const
|
||||||
|
{
|
||||||
|
return fTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum alignment Alignment() const
|
||||||
|
{
|
||||||
|
return fAlignment;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CanBeTruncated() const
|
||||||
|
{
|
||||||
|
return fCanBeTruncated;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 NeededWidth() const
|
||||||
|
{
|
||||||
|
return fNeededWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 MinWidth() const
|
||||||
|
{
|
||||||
|
return fMinWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 Width() const
|
||||||
|
{
|
||||||
|
return fWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetWidth(int32 width)
|
||||||
|
{
|
||||||
|
fWidth = width;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateNeededWidth(const BString& text)
|
||||||
|
{
|
||||||
|
// TODO: Full-width character support.
|
||||||
|
int32 textWidth = text.CountChars();
|
||||||
|
if (textWidth > fNeededWidth)
|
||||||
|
fNeededWidth = textWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
BString Format(const BString& text)
|
||||||
|
{
|
||||||
|
// TODO: Full-width character support.
|
||||||
|
int32 textWidth = text.CountChars();
|
||||||
|
if (textWidth == fWidth)
|
||||||
|
return text;
|
||||||
|
|
||||||
|
// truncate, if too long
|
||||||
|
if (textWidth > fWidth) {
|
||||||
|
BString result(text);
|
||||||
|
result.TruncateChars(fWidth);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// align, if too short
|
||||||
|
int32 missing = fWidth - textWidth;
|
||||||
|
switch (fAlignment) {
|
||||||
|
case B_ALIGN_LEFT:
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
BString result(text);
|
||||||
|
result.Append(' ', missing);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
case B_ALIGN_RIGHT:
|
||||||
|
{
|
||||||
|
BString result;
|
||||||
|
result.Append(' ', missing);
|
||||||
|
result.Append(text);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
case B_ALIGN_CENTER:
|
||||||
|
{
|
||||||
|
BString result;
|
||||||
|
result.Append(' ', missing / 2);
|
||||||
|
result.Append(text);
|
||||||
|
result.Append(' ', missing - missing / 2);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
BString fTitle;
|
||||||
|
enum alignment fAlignment;
|
||||||
|
bool fCanBeTruncated;
|
||||||
|
int32 fNeededWidth;
|
||||||
|
int32 fMinWidth;
|
||||||
|
int32 fWidth;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - TextTable
|
||||||
|
|
||||||
|
|
||||||
|
TextTable::TextTable()
|
||||||
|
:
|
||||||
|
fColumns(10, true),
|
||||||
|
fRows(100, true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TextTable::~TextTable()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
TextTable::CountColumns() const
|
||||||
|
{
|
||||||
|
return fColumns.CountItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TextTable::AddColumn(const BString& title, enum alignment align,
|
||||||
|
bool canTruncate)
|
||||||
|
{
|
||||||
|
Column* column = new Column(title, align, canTruncate);
|
||||||
|
if (!fColumns.AddItem(column)) {
|
||||||
|
delete column;
|
||||||
|
throw std::bad_alloc();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
TextTable::CountRows() const
|
||||||
|
{
|
||||||
|
return fRows.CountItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BString
|
||||||
|
TextTable::TextAt(int32 rowIndex, int32 columnIndex) const
|
||||||
|
{
|
||||||
|
BStringList* row = fRows.ItemAt(rowIndex);
|
||||||
|
if (row == NULL)
|
||||||
|
return BString();
|
||||||
|
return row->StringAt(columnIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TextTable::SetTextAt(int32 rowIndex, int32 columnIndex, const BString& text)
|
||||||
|
{
|
||||||
|
// If necessary append empty rows up to the specified row index.
|
||||||
|
while (rowIndex >= fRows.CountItems()) {
|
||||||
|
BStringList* row = new BStringList();
|
||||||
|
if (!fRows.AddItem(row)) {
|
||||||
|
delete row;
|
||||||
|
throw std::bad_alloc();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If necessary append empty strings up to the specified column index.
|
||||||
|
BStringList* row = fRows.ItemAt(rowIndex);
|
||||||
|
while (columnIndex >= row->CountStrings()) {
|
||||||
|
if (!row->Add(BString()))
|
||||||
|
throw std::bad_alloc();
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the text
|
||||||
|
if (!row->Replace(columnIndex, text))
|
||||||
|
throw std::bad_alloc();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TextTable::Print(int32 maxWidth)
|
||||||
|
{
|
||||||
|
int32 columnCount = fColumns.CountItems();
|
||||||
|
if (columnCount == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// determine the column widths
|
||||||
|
int32 rowCount = fRows.CountItems();
|
||||||
|
for (int32 rowIndex = 0; rowIndex < rowCount; rowIndex++) {
|
||||||
|
BStringList* row = fRows.ItemAt(rowIndex);
|
||||||
|
int32 rowColumnCount = std::min(row->CountStrings(), columnCount);
|
||||||
|
for (int32 columnIndex = 0; columnIndex < rowColumnCount;
|
||||||
|
columnIndex++) {
|
||||||
|
fColumns.ItemAt(columnIndex)->UpdateNeededWidth(
|
||||||
|
row->StringAt(columnIndex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 neededWidth = (columnCount - 1) * 2;
|
||||||
|
// spacing
|
||||||
|
for (int32 i = 0; i < columnCount; i++)
|
||||||
|
neededWidth += fColumns.ItemAt(i)->NeededWidth();
|
||||||
|
|
||||||
|
int32 width = neededWidth;
|
||||||
|
int32 missingWidth = neededWidth - std::min(maxWidth, neededWidth);
|
||||||
|
|
||||||
|
for (int32 i = 0; i < columnCount; i++) {
|
||||||
|
Column* column = fColumns.ItemAt(i);
|
||||||
|
if (missingWidth > 0 && column->CanBeTruncated()) {
|
||||||
|
int32 truncateBy = std::min(missingWidth,
|
||||||
|
column->NeededWidth() - column->MinWidth());
|
||||||
|
column->SetWidth(column->NeededWidth() - truncateBy);
|
||||||
|
missingWidth -= truncateBy;
|
||||||
|
width -= truncateBy;
|
||||||
|
} else
|
||||||
|
column->SetWidth(column->NeededWidth());
|
||||||
|
}
|
||||||
|
|
||||||
|
// print the header
|
||||||
|
BString line;
|
||||||
|
for (int32 i = 0; i < columnCount; i++) {
|
||||||
|
if (i > 0)
|
||||||
|
line << " ";
|
||||||
|
|
||||||
|
Column* column = fColumns.ItemAt(i);
|
||||||
|
line << column->Format(column->Title());
|
||||||
|
}
|
||||||
|
line << '\n';
|
||||||
|
fputs(line.String(), stdout);
|
||||||
|
|
||||||
|
line.SetTo('-', width);
|
||||||
|
line << '\n';
|
||||||
|
fputs(line.String(), stdout);
|
||||||
|
|
||||||
|
// print the rows
|
||||||
|
for (int32 rowIndex = 0; rowIndex < rowCount; rowIndex++) {
|
||||||
|
line.Truncate(0);
|
||||||
|
BStringList* row = fRows.ItemAt(rowIndex);
|
||||||
|
for (int32 columnIndex = 0; columnIndex < columnCount; columnIndex++) {
|
||||||
|
if (columnIndex > 0)
|
||||||
|
line << " ";
|
||||||
|
|
||||||
|
line << fColumns.ItemAt(columnIndex)->Format(
|
||||||
|
row->StringAt(columnIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
line << '\n';
|
||||||
|
fputs(line.String(), stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef TEXT_TABLE_H
|
||||||
|
#define TEXT_TABLE_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <InterfaceDefs.h>
|
||||||
|
#include <ObjectList.h>
|
||||||
|
#include <StringList.h>
|
||||||
|
|
||||||
|
|
||||||
|
class TextTable {
|
||||||
|
public:
|
||||||
|
TextTable();
|
||||||
|
~TextTable();
|
||||||
|
|
||||||
|
int32 CountColumns() const;
|
||||||
|
void AddColumn(const BString& title,
|
||||||
|
enum alignment align = B_ALIGN_LEFT,
|
||||||
|
bool canTruncate = false);
|
||||||
|
|
||||||
|
int32 CountRows() const;
|
||||||
|
BString TextAt(int32 rowIndex, int32 columnIndex) const;
|
||||||
|
void SetTextAt(int32 rowIndex, int32 columnIndex,
|
||||||
|
const BString& text);
|
||||||
|
|
||||||
|
void Print(int32 maxWidth);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Column;
|
||||||
|
typedef BObjectList<Column> ColumnList;
|
||||||
|
typedef BObjectList<BStringList> RowList;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ColumnList fColumns;
|
||||||
|
RowList fRows;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // TEXT_TABLE_H
|
||||||
@@ -15,17 +15,18 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
#include <package/solver/SolverPackage.h>
|
#include <package/solver/SolverPackage.h>
|
||||||
|
|
||||||
#include "Command.h"
|
#include "Command.h"
|
||||||
#include "PackageManager.h"
|
#include "PackageManager.h"
|
||||||
#include "pkgman.h"
|
#include "pkgman.h"
|
||||||
|
#include "TextTable.h"
|
||||||
|
|
||||||
|
|
||||||
// TODO: internationalization!
|
// TODO: internationalization!
|
||||||
// The printing code will need serious attention wrt. dealing with UTF-8 and,
|
// The table code doesn't support full-width characters yet.
|
||||||
// even worse, full-width characters.
|
|
||||||
|
|
||||||
|
|
||||||
using namespace BPackageKit;
|
using namespace BPackageKit;
|
||||||
@@ -42,10 +43,20 @@ static const char* const kLongUsage =
|
|||||||
"Options:\n"
|
"Options:\n"
|
||||||
" -a, --all\n"
|
" -a, --all\n"
|
||||||
" List all packages. Specified instead of <search-string>.\n"
|
" List all packages. Specified instead of <search-string>.\n"
|
||||||
|
" -D, --details\n"
|
||||||
|
" Print more details. Matches in each installation location and each\n"
|
||||||
|
" repository will be listed individually with their version.\n"
|
||||||
" -i, --installed-only\n"
|
" -i, --installed-only\n"
|
||||||
" Only find installed packages.\n"
|
" Only find installed packages.\n"
|
||||||
" -u, --uninstalled-only\n"
|
" -u, --uninstalled-only\n"
|
||||||
" Only find not installed packages.\n"
|
" Only find not installed packages.\n"
|
||||||
|
"\n"
|
||||||
|
"Status flags in non-detailed listings:\n"
|
||||||
|
" S - installed in system with a matching version in a repository\n"
|
||||||
|
" s - installed in system without a matching version in a repository\n"
|
||||||
|
" H - installed in home with a matching version in a repository\n"
|
||||||
|
" h - installed in home without a matching version in a repository\n"
|
||||||
|
" v - multiple different versions available in repositories\n"
|
||||||
"\n";
|
"\n";
|
||||||
|
|
||||||
|
|
||||||
@@ -65,16 +76,64 @@ get_terminal_width()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct PackageComparator {
|
||||||
|
PackageComparator(const BSolverRepository* systemRepository,
|
||||||
|
const BSolverRepository* homeRepository)
|
||||||
|
:
|
||||||
|
fSystemRepository(systemRepository),
|
||||||
|
fHomeRepository(homeRepository)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int operator()(const BSolverPackage* a, const BSolverPackage* b) const
|
||||||
|
{
|
||||||
|
int cmp = a->Name().Compare(b->Name());
|
||||||
|
if (cmp != 0)
|
||||||
|
return cmp;
|
||||||
|
|
||||||
|
// Names are equal. Sort by installation location and then by repository
|
||||||
|
// name.
|
||||||
|
if (a->Repository() == b->Repository())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (a->Repository() == fSystemRepository)
|
||||||
|
return -1;
|
||||||
|
if (b->Repository() == fSystemRepository)
|
||||||
|
return 1;
|
||||||
|
if (a->Repository() == fHomeRepository)
|
||||||
|
return -1;
|
||||||
|
if (b->Repository() == fHomeRepository)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return a->Repository()->Name().Compare(b->Repository()->Name());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const BSolverRepository* fSystemRepository;
|
||||||
|
const BSolverRepository* fHomeRepository;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
compare_packages(const BSolverPackage* a, const BSolverPackage* b,
|
||||||
|
void* comparator)
|
||||||
|
{
|
||||||
|
return (*(PackageComparator*)comparator)(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
SearchCommand::Execute(int argc, const char* const* argv)
|
SearchCommand::Execute(int argc, const char* const* argv)
|
||||||
{
|
{
|
||||||
bool installedOnly = false;
|
bool installedOnly = false;
|
||||||
bool uninstalledOnly = false;
|
bool uninstalledOnly = false;
|
||||||
bool listAll = false;
|
bool listAll = false;
|
||||||
|
bool details = false;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
static struct option sLongOptions[] = {
|
static struct option sLongOptions[] = {
|
||||||
{ "all", no_argument, 0, 'a' },
|
{ "all", no_argument, 0, 'a' },
|
||||||
|
{ "details", no_argument, 0, 'D' },
|
||||||
{ "help", no_argument, 0, 'h' },
|
{ "help", no_argument, 0, 'h' },
|
||||||
{ "installed-only", no_argument, 0, 'i' },
|
{ "installed-only", no_argument, 0, 'i' },
|
||||||
{ "uninstalled-only", no_argument, 0, 'u' },
|
{ "uninstalled-only", no_argument, 0, 'u' },
|
||||||
@@ -82,7 +141,7 @@ SearchCommand::Execute(int argc, const char* const* argv)
|
|||||||
};
|
};
|
||||||
|
|
||||||
opterr = 0; // don't print errors
|
opterr = 0; // don't print errors
|
||||||
int c = getopt_long(argc, (char**)argv, "ahiu", sLongOptions, NULL);
|
int c = getopt_long(argc, (char**)argv, "aDhiu", sLongOptions, NULL);
|
||||||
if (c == -1)
|
if (c == -1)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -91,6 +150,10 @@ SearchCommand::Execute(int argc, const char* const* argv)
|
|||||||
listAll = true;
|
listAll = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'D':
|
||||||
|
details = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
PrintUsageAndExit(false);
|
PrintUsageAndExit(false);
|
||||||
break;
|
break;
|
||||||
@@ -139,66 +202,93 @@ SearchCommand::Execute(int argc, const char* const* argv)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sort packages by name and installation location/repository
|
||||||
|
const BSolverRepository* systemRepository
|
||||||
|
= static_cast<const BSolverRepository*>(
|
||||||
|
packageManager.SystemRepository());
|
||||||
|
const BSolverRepository* homeRepository
|
||||||
|
= static_cast<const BSolverRepository*>(
|
||||||
|
packageManager.HomeRepository());
|
||||||
|
PackageComparator comparator(systemRepository, homeRepository);
|
||||||
|
packages.SortItems(&compare_packages, &comparator);
|
||||||
|
|
||||||
// print table
|
// print table
|
||||||
|
TextTable table;
|
||||||
|
|
||||||
// determine column widths
|
if (details) {
|
||||||
BString installedColumnTitle("Installed");
|
table.AddColumn("Repository");
|
||||||
BString nameColumnTitle("Name");
|
table.AddColumn("Name");
|
||||||
BString descriptionColumnTitle("Description");
|
table.AddColumn("Version");
|
||||||
|
table.AddColumn("Arch");
|
||||||
|
|
||||||
int installedColumnWidth = installedColumnTitle.Length();
|
int32 packageCount = packages.CountItems();
|
||||||
int nameColumnWidth = nameColumnTitle.Length();
|
for (int32 i = 0; i < packageCount; i++) {
|
||||||
int descriptionColumnWidth = descriptionColumnTitle.Length();
|
BSolverPackage* package = packages.ItemAt(i);
|
||||||
|
|
||||||
int32 packageCount = packages.CountItems();
|
BString repository = "";
|
||||||
for (int32 i = 0; i < packageCount; i++) {
|
if (package->Repository() == systemRepository)
|
||||||
BSolverPackage* package = packages.ItemAt(i);
|
repository = "<system>";
|
||||||
nameColumnWidth = std::max(nameColumnWidth,
|
else if (package->Repository() == homeRepository)
|
||||||
(int)package->Name().Length());
|
repository = "<home>";
|
||||||
descriptionColumnWidth = std::max(descriptionColumnWidth,
|
else
|
||||||
(int)package->Info().Summary().Length());
|
repository = package->Repository()->Name();
|
||||||
|
|
||||||
|
table.SetTextAt(i, 0, repository);
|
||||||
|
table.SetTextAt(i, 1, package->Name());
|
||||||
|
table.SetTextAt(i, 2, package->Version().ToString());
|
||||||
|
table.SetTextAt(i, 3, package->Info().ArchitectureName());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
table.AddColumn("Status");
|
||||||
|
table.AddColumn("Name");
|
||||||
|
table.AddColumn("Description", B_ALIGN_LEFT, true);
|
||||||
|
|
||||||
|
int32 packageCount = packages.CountItems();
|
||||||
|
for (int32 i = 0; i < packageCount;) {
|
||||||
|
// find the next group of equally named packages
|
||||||
|
int32 groupStart = i;
|
||||||
|
std::set<BPackageVersion> versions;
|
||||||
|
BSolverPackage* systemPackage = NULL;
|
||||||
|
BSolverPackage* homePackage = NULL;
|
||||||
|
while (i < packageCount) {
|
||||||
|
BSolverPackage* package = packages.ItemAt(i);
|
||||||
|
if (i > groupStart
|
||||||
|
&& package->Name() != packages.ItemAt(groupStart)->Name()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (package->Repository() == systemRepository)
|
||||||
|
systemPackage = package;
|
||||||
|
else if (package->Repository() == homeRepository)
|
||||||
|
homePackage = package;
|
||||||
|
else
|
||||||
|
versions.insert(package->Version());
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add a table row for the group
|
||||||
|
BString status;
|
||||||
|
if (systemPackage != NULL) {
|
||||||
|
status << (versions.find(systemPackage->Version())
|
||||||
|
!= versions.end() ? 'S' : 's');
|
||||||
|
}
|
||||||
|
if (homePackage != NULL) {
|
||||||
|
status << (versions.find(homePackage->Version())
|
||||||
|
!= versions.end() ? 'H' : 'h');
|
||||||
|
}
|
||||||
|
if (versions.size() > 1)
|
||||||
|
status << 'v';
|
||||||
|
|
||||||
|
int32 rowIndex = table.CountRows();
|
||||||
|
BSolverPackage* package = packages.ItemAt(groupStart);
|
||||||
|
table.SetTextAt(rowIndex, 0, status);
|
||||||
|
table.SetTextAt(rowIndex, 1, package->Name());
|
||||||
|
table.SetTextAt(rowIndex, 2, package->Info().Summary());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// print header
|
table.Print(get_terminal_width());
|
||||||
BString header;
|
|
||||||
header.SetToFormat("%-*s %-*s %s",
|
|
||||||
installedColumnWidth, installedColumnTitle.String(),
|
|
||||||
nameColumnWidth, nameColumnTitle.String(),
|
|
||||||
descriptionColumnTitle.String());
|
|
||||||
printf("%s\n", header.String());
|
|
||||||
|
|
||||||
int minLineWidth = header.Length();
|
|
||||||
int lineWidth = minLineWidth + descriptionColumnWidth
|
|
||||||
- descriptionColumnTitle.Length();
|
|
||||||
int terminalWidth = get_terminal_width();
|
|
||||||
if (lineWidth > terminalWidth) {
|
|
||||||
// truncate description
|
|
||||||
int actualLineWidth = std::max(minLineWidth, terminalWidth);
|
|
||||||
descriptionColumnWidth -= lineWidth - actualLineWidth;
|
|
||||||
lineWidth = actualLineWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
header.SetTo('-', lineWidth);
|
|
||||||
printf("%s\n", header.String());
|
|
||||||
|
|
||||||
// print packages
|
|
||||||
for (int32 i = 0; i < packageCount; i++) {
|
|
||||||
BSolverPackage* package = packages.ItemAt(i);
|
|
||||||
|
|
||||||
const char* installed = "";
|
|
||||||
if (package->Repository() == static_cast<const BSolverRepository*>(
|
|
||||||
packageManager.SystemRepository()))
|
|
||||||
installed = "system";
|
|
||||||
else if (package->Repository() == static_cast<const BSolverRepository*>(
|
|
||||||
packageManager.HomeRepository()))
|
|
||||||
installed = "home";
|
|
||||||
|
|
||||||
printf("%-*s %-*s %-*.*s\n",
|
|
||||||
installedColumnWidth, installed,
|
|
||||||
nameColumnWidth, package->Name().String(),
|
|
||||||
descriptionColumnWidth, descriptionColumnWidth,
|
|
||||||
package->Info().Summary().String());
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user