All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.core.Ls.kt Maven / Gradle / Ivy

There is a newer version: 0.0.87
Show newest version
package pl.mareklangiewicz.kommand.core

import kotlinx.coroutines.flow.*
import okio.Path
import pl.mareklangiewicz.annotations.DelicateApi
import pl.mareklangiewicz.kground.io.P
import pl.mareklangiewicz.kground.namelowords
import pl.mareklangiewicz.kommand.*
import pl.mareklangiewicz.kommand.core.LsOpt.*
import pl.mareklangiewicz.kommand.core.LsOpt.IndicatorStyle.*
import pl.mareklangiewicz.udata.strf

fun lsRegFiles(dir: Path, wHidden: Boolean = false): ReducedKommand> =
  ls(dir, wHidden = wHidden, wIndicator = Slash).reducedOut { toList().filter { !it.endsWith('/') }.map { it.P } }

fun lsSubDirs(dir: Path, wHidden: Boolean = false): ReducedKommand> =
  ls(dir, wHidden = wHidden, wIndicator = Slash).reducedOut {
    toList().filter { it.endsWith('/') }.map { it.dropLast(1).P }
  }

/** It always skips special "." and ".." (as it should) even if wHidden = true */
fun lsCountChildren(path: Path, wHidden: Boolean): ReducedKommand =
  ls(path, wHidden = wHidden).reducedOut { count() }

fun lsIsEmpty(path: Path): ReducedKommand = lsCountChildren(path, true)
  .reducedMap { this == 0 }

/**
 * Generally null values mean: default, so it depends on the underlying system (not necessarily "none").
 * For example, on my machine "man ls" says that default indicator-style is "none",
 * but when I try it (no alias, output piped to file), it works as if it was "slash".
 * BTW default color should always be fine (null == default == "auto"),
 * because it only adds colors when stdout is terminal (not piped to any file or sth)
 */
fun ls(
  vararg paths: Path,
  wHidden: Boolean = false,
  wIndicator: IndicatorStyle? = null,
  wColor: ColorType? = null,
  wDirsFirst: Boolean = false,
  init: Ls.() -> Unit = {},
) = Ls().apply {
  for (p in paths) +p.strf
  if (wHidden) -AlmostAll
  wIndicator?.let { -Indicator(it) }
  wColor?.let { -Color(it) }
  if (wDirsFirst) -DirsFirst
  init()
}


/**
 * [linux man](https://man7.org/linux/man-pages/man1/ls.1.html)
 * Details: [gnu ls invocation](https://www.gnu.org/software/coreutils/manual/html_node/ls-invocation.html)
 */
@OptIn(DelicateApi::class)
data class Ls(
  override val opts: MutableList = mutableListOf(),
  override val nonopts: MutableList = mutableListOf(),
) : KommandTypical {
  override val name get() = "ls"
}

@OptIn(DelicateApi::class)
interface LsOpt : KOptTypical {

  // region [GNU Common Opts]
  // https://www.gnu.org/software/coreutils/manual/html_node/Common-options.html
  data object Help : KOptLN(), LsOpt // Don't risk short -h (ambiguity: sudo -h host; ls -h (human-readable), etc.)
  data object Version : KOptLN(), LsOpt // Don't risk short -v (ambiguity with "verbose" for many commands)
  data object EOOpt : KOptL(""), LsOpt
  // endregion [GNU Common Opts]

  // region [GNU Block Size Opts]
  /** https://www.gnu.org/software/coreutils/manual/html_node/Block-size.html */
  data class Block(val size: String) : KOptLN(size), LsOpt
  data object Block1K : KOptS("k"), LsOpt
  data object BlockHuman : KOptS("h"), LsOpt
  data object BlockHumanSI : KOptL("si"), LsOpt
  // endregion [GNU Block Size Opts]

  /** list one file per line even when stdout is terminal */
  data object One : KOptS("1"), LsOpt

  /** end each output line with NUL, not newline */
  data object Zero : KOptLN(), LsOpt

  /** do not ignore entries starting with "." */
  data object All : KOptS("a"), LsOpt
  /** do not list implied "." and ".." */
  data object AlmostAll : KOptS("A"), LsOpt

  data object Author : KOptLN(), LsOpt

  data object Escape : KOptLN(), LsOpt

  data object IgnoreBackups : KOptLN(), LsOpt

  data object ListByColumns : KOptS("C"), LsOpt
  data object ListByLines : KOptS("x"), LsOpt

  data class Color(val type: ColorType) : KOptLN(type.namelowords("")), LsOpt
  enum class ColorType { Always, Auto, Never }

  data object Directory : KOptS("d"), LsOpt

  data object Dired : KOptLN(), LsOpt

  /** do not sort, enable -aU, disable -ls --color */
  data object Raw : KOptS("f"), LsOpt

  /**
   * Append indicator (one of *=/>@|) to entries.
   * The file type indicators are ‘/’ for directories, ‘@’ for symbolic links,
   * ‘|’ for FIFOs, ‘=’ for sockets, ‘>’ for doors, and nothing for regular files.
   * Also, for regular files that are executable, append ‘*’.
   */
  data object Classify : KOptS("F"), LsOpt

  /** Like [Classify], except do not add the `*` for executable files. */
  data object ClassifyFileType : KOptL("file-type"), LsOpt

  data class Format(val type: FormatType) : KOptLN(type.namelowords("")), LsOpt
  enum class FormatType { Across, Commas, Horizontal, Long, SingleColumn, Verbose, Vertical }

  /** like -l --time-style=full-iso */
  data object FullTime : KOptLN(), LsOpt

  data object DirsFirst : KOptL("group-directories-first"), LsOpt

  data object NoGroup : KOptS("G"), LsOpt

  data object LongFormat : KOptS("l"), LsOpt // option name is not just Long to avoid clash with Long data type
  data object LongWithoutOwner : KOptS("g"), LsOpt
  data object LongWithoutGroup : KOptS("o"), LsOpt

  data object Dereference : KOptLN(), LsOpt
  data object DereferenceCommandLine : KOptLN(), LsOpt
  data object DereferenceCommandLineSymlinkToDir : KOptLN(), LsOpt

  data class Hide(val pattern: String) : KOptLN(pattern), LsOpt
  /** print ? instead of nongraphic characters */
  data object HideControlChars : KOptLN(), LsOpt
  /** show nongraphic characters as-is (the default, unless program is 'ls' and output is a terminal) */
  data object ShowControlChars : KOptLN(), LsOpt

  data class Hyperlink(val type: HyperlinkType) : KOptLN(type.namelowords("")), LsOpt
  enum class HyperlinkType { Always, Auto, Never }

  data class Indicator(val style: IndicatorStyle) : KOptL("indicator-style", style.namelowords("-")), LsOpt
  enum class IndicatorStyle { None, Slash, FileType, Classify }

  data object IndicatorSlash : KOptS("p"), LsOpt

  data object INode : KOptL("inode"), LsOpt

  data class Ignore(val pattern: String) : KOptLN(pattern), LsOpt

  data object Commas : KOptS("m"), LsOpt

  data object NumericUidGid : KOptLN(), LsOpt

  data object Literal : KOptLN(), LsOpt

  data object QuoteName : KOptLN(), LsOpt

  data class Quoting(val style: QuotingStyle) : KOptL("quoting-style", style.namelowords("-")), LsOpt
  enum class QuotingStyle { Literal, Locale, Shell, ShellAlways, ShellEscape, ShellEscapeAlways, C, Escape }

  data object Reverse : KOptS("r"), LsOpt

  data object Recursive : RmOpt, KOptLN() // Don't risk short -r or -R (better to be explicit about RECURSIVE)

  data object Size : KOptS("s"), LsOpt

  data class Sort(val type: SortType) : KOptLN(type.namelowords("")), LsOpt
  enum class SortType { None, Size, Time, Version, Extension }
  /** largest first */
  data object SortBySize : KOptS("S"), LsOpt
  data object SortByTime : KOptS("t"), LsOpt
  /** do not sort */
  data object SortByNothing : KOptS("U"), LsOpt
  /** Natural sort of (version) numbers within text */
  data object SortByVersion : KOptS("v"), LsOpt
  data object SortByExtension : KOptS("X"), LsOpt

  data class Time(val type: TimeType) : KOptLN(type.namelowords("")), LsOpt

  /**
   * There are duplicates:
   * last access time: ATime, Access, Use
   * last change time: CTime, Status
   * creation time: Birth, Creation
   */
  enum class TimeType { ATime, Access, Use, CTime, Status, Birth, Creation }

  data object TimeOfAccess : KOptS("u"), LsOpt
  data object TimeOfChange : KOptS("c"), LsOpt
  data object TimeOfBirth : KOptL("time", "birth"), LsOpt

  data class TimeStyle(val style: String) : KOptLN(style), LsOpt

  data class TabSize(val size: Int) : KOptL("tabsize", "$size"), LsOpt

  data class Width(val columns: Int) : KOptLN("$columns"), LsOpt

  data object PrintContext : KOptL("context"), LsOpt
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy