kv

ufko.org

# ---------------------------------------------------------------------
# Function: kv
# A minimalist's key-value manager for dict-like lists
# This function operates on lists where key-value pairs  are stored in
# an even number of elements. The list is modified in-place via reference,
# so no new list is returned.
#
# Arguments:
# @arg lstVar  The list variable name to operate on.
# @arg key     The key to get/set/add/delete.
# @arg value   The value to set for the given key (if provided).
#
# It allows the following operations on the list:
# - GET (fetch the value for a given key),
# - SET (set a value for a key, or update an existing one),
# - ADD (add a new key-value pair if the key doesn't exist),
# - DEL (delete a key-value pair by removing both the key and value).
#
# Special behavior:
# - If the value is "-" it deletes the key and its value
# - If the key is "-" (minus sign), the entire list is pretty printed.
# - The list must have an even number of elements to work correctly.
#
# Example usage:
# set lst {name Jack age 30}
# kv lst name      ;# -> Jack
# kv lst name John ;# Sets new name
# kv lst age       ;# -> 30
# kv lst city NYC  ;# Adds 'city' -> 'NYC'
# kv lst fullname {John Doe} ;# Adds 'fullname' -> 'John Doe'
# kv lst -         ;# Pretty prints the current list
# kv lst city -    ;# Deletes the city key and its value
#
# Returns the value associated with the key if GET operation, or an empty
# string if the key is not found. If a modification is made (SET/ADD),
# the list is updated in-place via reference, and the set value is returned.
# In the case of DELETE, the removed keyname is returned, or an empty string
# if the key was not found.
# ----------------------------------------------------------------------

proc kv {lstVar key {value {}}} {
  upvar 1 $lstVar lst
  set idx [lsearch -exact $lst $key]

  # Pretty print when key is "-"
  if {$key eq "-"} {
    puts "Pretty printing current list:"
    foreach {k v} $lst {
      puts "$k -> $v"
    }
    return
  }

  if {$value eq {}} {
    # get
    return [expr {$idx == -1 ? "" : [lindex $lst [expr {$idx + 1}]]}]
  } elseif {$value eq "-"} {
    # del
    if {$idx != -1} {
      set lst [lreplace $lst $idx [expr {$idx + 1}]]
    }
    return $key
  } elseif {$idx == -1} {
    # add
    lappend lst $key $value
  } else {
    # set
    ledit lst [expr {$idx + 1}] 1 $value
  }
  return $value
}