diff --git a/CHANGELOG.md b/CHANGELOG.md index 477d0f3..8aa85b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,8 @@ - fix result error when multiple stats applied to the same column. - `csvtk corr/watch`: - rewrite and fix bug, support choosing fields with column names. + - `csvtk pretty`: + - align-center and align-right for specific columns. [#240](https://github.com/shenwei356/csvtk/issues/240) - [csvtk v0.26.0](https://github.com/shenwei356/csvtk/releases/tag/v0.26.0) [![Github Releases (by Release)](https://img.shields.io/github/downloads/shenwei356/csvtk/v0.26.0/total.svg)](https://github.com/shenwei356/csvtk/releases/tag/v0.26.0) - `csvtk`: diff --git a/csvtk/cmd/pretty.go b/csvtk/cmd/pretty.go index 7f68f32..20a78e5 100644 --- a/csvtk/cmd/pretty.go +++ b/csvtk/cmd/pretty.go @@ -23,6 +23,7 @@ package cmd import ( "fmt" "runtime" + "strconv" "strings" "github.com/shenwei356/stable" @@ -124,8 +125,8 @@ Styles: } runtime.GOMAXPROCS(config.NumCPUs) - alignRight := getFlagBool(cmd, "align-right") - alignCenter := getFlagBool(cmd, "align-center") + alignRights := getFlagStringSlice(cmd, "align-right") + alignCenters := getFlagStringSlice(cmd, "align-center") separator := getFlagString(cmd, "separator") minWidth := getFlagNonNegativeInt(cmd, "min-width") maxWidth := getFlagNonNegativeInt(cmd, "max-width") @@ -181,7 +182,7 @@ Styles: style = "default" } - tbl := stable.New().AlignLeft() + tbl := stable.New() tbl.WrapDelimiter(rune(wrapDelimiter[0])) @@ -197,12 +198,7 @@ Styles: if maxWidth > 0 { tbl.MaxWidth(maxWidth) } - if alignRight { - tbl.AlignRight() - } - if alignCenter { - tbl.AlignCenter() - } + if clip { tbl.ClipCell(clipMark) } @@ -210,6 +206,7 @@ Styles: tbl.Writer(outfh, uint(bufRows)) checkFirstLine := true + var header []stable.Column for record := range csvReader.Ch { if record.Err != nil { checkError(record.Err) @@ -218,10 +215,62 @@ Styles: if checkFirstLine { checkFirstLine = false + ncols := len(record.All) + if config.ShowRowNumber { + ncols++ + } + header = make([]stable.Column, ncols) + + colnames2fileds := make(map[string][]int, ncols) + + var i int + var col string + var ok bool if !config.NoHeaderRow || record.IsHeaderRow { - tbl.Header(record.Selected) - continue + for i, col = range record.All { + if config.ShowRowNumber { + i++ + } + if _, ok = colnames2fileds[col]; !ok { + colnames2fileds[col] = []int{i} + } else { + colnames2fileds[col] = append(colnames2fileds[col], i) + } + } + + for i, col = range record.Selected { + header[i].Header = col + } } + + for i = range record.All { + col = strconv.Itoa(i + 1) + if _, ok = colnames2fileds[col]; !ok { + colnames2fileds[col] = []int{i} + } else { + colnames2fileds[col] = append(colnames2fileds[col], i) + } + } + + for _, col = range alignCenters { + for _, i = range colnames2fileds[col] { + if config.ShowRowNumber { + i++ + } + header[i].Align = stable.AlignCenter + } + } + for _, col = range alignRights { + for _, i = range colnames2fileds[col] { + if config.ShowRowNumber { + i++ + } + header[i].Align = stable.AlignRight + } + } + + tbl.HeaderWithFormat(header) + continue } tbl.AddRowStringSlice(record.Selected) @@ -235,8 +284,8 @@ Styles: func init() { RootCmd.AddCommand(prettyCmd) prettyCmd.Flags().StringP("separator", "s", " ", "fields/columns separator") - prettyCmd.Flags().BoolP("align-right", "r", false, "align right") - prettyCmd.Flags().BoolP("align-center", "m", false, "align center/middle") + prettyCmd.Flags().StringSliceP("align-right", "r", []string{}, "align right for selected columns (field index or column name)") + prettyCmd.Flags().StringSliceP("align-center", "m", []string{}, "align center/middle for selected columns (field index or column name)") prettyCmd.Flags().IntP("min-width", "w", 0, "min width") prettyCmd.Flags().IntP("max-width", "W", 0, "max width") diff --git a/doc/docs/usage.md b/doc/docs/usage.md index 616bb49..2f4dbe0 100644 --- a/doc/docs/usage.md +++ b/doc/docs/usage.md @@ -663,8 +663,8 @@ Usage: csvtk pretty [flags] Flags: - -m, --align-center align center/middle - -r, --align-right align right + -m, --align-center strings align center/middle for selected columns (field index or column name) + -r, --align-right strings align right for selected columns (field index or column name) -n, --buf-rows int the number of rows to determine the min and max widths (default 128) --clip clip longer cell instead of wrapping --clip-mark string clip mark (default "...") @@ -674,7 +674,7 @@ Flags: -s, --separator string fields/columns separator (default " ") -S, --style string output syle. available vaules: default, plain, simple, grid, light, bold, double. check https://github.com/shenwei356/stable - -x, --wrap-delimiter string delimiter for wrapping cells (default " ") + -x, --wrap-delimiter string delimiter for wrapping cells (default " ``` @@ -691,17 +691,22 @@ Examples: 1 Robert Thompson abc NA Robert Abel 123 -2. align right - - $ csvtk pretty testdata/names.csv -r - id first_name last_name username - -- ---------- --------- -------- - 11 Rob Pike rob - 2 Ken Thompson ken - 4 Robert Griesemer gri - 1 Robert Thompson abc - NA Robert Abel 123 - +2. align right/center for some columns + + $ csvtk pretty testdata/names.csv -r 1,username -m first_name + ┏━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━┓ + ┃ id ┃ first_name ┃ last_name ┃ username ┃ + ┣━━━━╋━━━━━━━━━━━━╋━━━━━━━━━━━╋━━━━━━━━━━┫ + ┃ 11 ┃ Rob ┃ Pike ┃ rob ┃ + ┣━━━━╋━━━━━━━━━━━━╋━━━━━━━━━━━╋━━━━━━━━━━┫ + ┃ 2 ┃ Ken ┃ Thompson ┃ ken ┃ + ┣━━━━╋━━━━━━━━━━━━╋━━━━━━━━━━━╋━━━━━━━━━━┫ + ┃ 4 ┃ Robert ┃ Griesemer ┃ gri ┃ + ┣━━━━╋━━━━━━━━━━━━╋━━━━━━━━━━━╋━━━━━━━━━━┫ + ┃ 1 ┃ Robert ┃ Thompson ┃ abc ┃ + ┣━━━━╋━━━━━━━━━━━━╋━━━━━━━━━━━╋━━━━━━━━━━┫ + ┃ NA ┃ Robert ┃ Abel ┃ 123 ┃ + ┗━━━━┻━━━━━━━━━━━━┻━━━━━━━━━━━┻━━━━━━━━━━┛ 3. custom separator