Repository: JanDeDobbeleer/oh-my-posh
Pull request #931 (2021-09-03 18:59:00)

feat: memory segment
### Prerequisites

- [x] I have read and understood the `CONTRIBUTING` guide
- [x] The commit message follows the [conventional commits][cc] guidelines
- [x] Tests for the changes have been added (for bug fixes/features)
- [x] Docs have been added / updated (for bug fixes/features)

### Description

This adds a segment for displaying used memory percentage.


Patch:
diff --git a/docs/docs/memory.md b/docs/docs/memory.md
new file mode 100644
index 00000000..0055a8c6
--- /dev/null
+++ b/docs/docs/memory.md
@@ -0,0 +1,29 @@
+---
+id: memory
+title: Memory
+sidebar_label: Memory
+---
+
+## Memory
+
+Display memory usage percentage.
+
+## Sample Configuration
+
+```json
+{
+  "type": "memory",
+  "style": "powerline",
+  "foreground": "#26C6DA",
+  "background": "#2f2f2f",
+  "properties": {
+    "precision": 1,
+    "prefix": " \uf85a ",
+    "postfix": "% "
+  }
+}
+```
+
+## Properties
+
+- precision: `int` - the number of decimal places to show - defaults to `0`
diff --git a/docs/sidebars.js b/docs/sidebars.js
index a1da862e..d5efa838 100644
--- a/docs/sidebars.js
+++ b/docs/sidebars.js
@@ -57,6 +57,7 @@ module.exports = {
         "text",
         "time",
         "ytm",
+        "memory",
       ],
     },
     {
diff --git a/src/go.mod b/src/go.mod
index 99467eb2..3bec93c4 100644
--- a/src/go.mod
+++ b/src/go.mod
@@ -20,6 +20,7 @@ require (
 	github.com/huandu/xstrings v1.3.2 // indirect
 	github.com/mitchellh/copystructure v1.2.0 // indirect
 	github.com/mitchellh/mapstructure v1.4.1
+	github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58
 	github.com/sergi/go-diff v1.2.0 // indirect
 	github.com/shirou/gopsutil v3.21.8+incompatible
 	github.com/smartystreets/goconvey v1.6.4 // indirect
diff --git a/src/go.sum b/src/go.sum
index cb5361b3..5d8e69c0 100644
--- a/src/go.sum
+++ b/src/go.sum
@@ -90,6 +90,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
 github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
 github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
+github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
diff --git a/src/segment.go b/src/segment.go
index 985b7333..012d885f 100644
--- a/src/segment.go
+++ b/src/segment.go
@@ -123,6 +123,8 @@ const (
 	Rust SegmentType = "rust"
 	// OWM writes the weather coming from openweatherdata
 	OWM SegmentType = "owm"
+	// Memory writes used memory percentage
+	Memory SegmentType = "memory"
 )
 
 func (segment *Segment) string() string {
@@ -264,6 +266,7 @@ func (segment *Segment) mapSegmentWithWriter(env environmentInfo) error {
 		Dart:          &dart{},
 		Nbgv:          &nbgv{},
 		Rust:          &rust{},
+		Memory:        &memory{},
 	}
 	if writer, ok := functions[segment.Type]; ok {
 		props := &properties{
diff --git a/src/segment_memory.go b/src/segment_memory.go
new file mode 100644
index 00000000..e27e0e76
--- /dev/null
+++ b/src/segment_memory.go
@@ -0,0 +1,36 @@
+package main
+
+import (
+	"strconv"
+
+	mem "github.com/pbnjay/memory"
+)
+
+type memory struct {
+	props       *properties
+	env         environmentInfo
+	TotalMemory uint64
+	FreeMemory  uint64
+}
+
+const (
+	Precision Property = "precision"
+)
+
+func (n *memory) enabled() bool {
+	return true
+}
+
+func (n *memory) string() string {
+	// 100.0 / total * used
+	percentage := 100.0 / float64(n.TotalMemory) * float64(n.TotalMemory-n.FreeMemory)
+	text := strconv.FormatFloat(percentage, 'f', n.props.getInt(Precision, 0), 64)
+	return text
+}
+
+func (n *memory) init(props *properties, env environmentInfo) {
+	n.props = props
+	n.env = env
+	n.TotalMemory = mem.TotalMemory()
+	n.FreeMemory = mem.FreeMemory()
+}
diff --git a/themes/schema.json b/themes/schema.json
index fd34d0f1..54b38885 100644
--- a/themes/schema.json
+++ b/themes/schema.json
@@ -168,7 +168,8 @@
             "crystal",
             "dart",
             "rust",
-            "owm"
+            "owm",
+            "memory"
           ]
         },
         "style": {
@@ -1637,6 +1638,29 @@
             "title": "Posh-Git Segment",
             "description": "https://ohmyposh.dev/docs/poshgit"
           }
+        },
+        {
+          "if": {
+            "properties": {
+              "type": { "const": "memory" }
+            }
+          },
+          "then": {
+            "title": "Get used memory percentage",
+            "description": "https://ohmyposh.dev/docs/memory",
+            "properties": {
+              "properties": {
+                "properties": {
+                  "precision": {
+                    "type": "integer",
+                    "title": "Precision",
+                    "description": "number of decimal places to show",
+                    "default": 0
+                  }
+                }
+              }
+            }
+          }
         }
       ]
     }


Test patch:
diff --git a/src/segment_memory_test.go b/src/segment_memory_test.go
new file mode 100644
index 00000000..e735beff
--- /dev/null
+++ b/src/segment_memory_test.go
@@ -0,0 +1,29 @@
+package main
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestMemory(t *testing.T) {
+	cases := []struct {
+		Case           string
+		ExpectedString string
+		Memory         memory
+		Precision      int
+	}{
+		{Case: "50", ExpectedString: "50", Memory: memory{FreeMemory: 50, TotalMemory: 100}},
+		{Case: "50.0", ExpectedString: "50.0", Memory: memory{FreeMemory: 50, TotalMemory: 100}, Precision: 1},
+	}
+
+	for _, tc := range cases {
+		tc.Memory.env = new(MockedEnvironment)
+		tc.Memory.props = &properties{
+			values: map[Property]interface{}{
+				Precision: tc.Precision,
+			},
+		}
+		assert.Equal(t, tc.ExpectedString, tc.Memory.string(), tc.Case)
+	}
+}