forked from colonelpanic/dotfiles
		
	Merge branch 'master' of github.com:IvanMalison/dotfiles
This commit is contained in:
		
							
								
								
									
										2
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							| @@ -1,6 +1,6 @@ | ||||
| [submodule "dotfiles/config/taffybar/taffybar"] | ||||
| 	path = dotfiles/config/taffybar/taffybar | ||||
| 	url = ../taffybar.git | ||||
| 	url = ../../travitch/taffybar.git | ||||
| [submodule "dotfiles/xmonad/xmonad"] | ||||
| 	path = dotfiles/config/xmonad/xmonad | ||||
| 	url = ../xmonad.git | ||||
|   | ||||
| @@ -18,10 +18,12 @@ executable imalison-taffybar | ||||
|                      , containers | ||||
|                      , directory | ||||
|                      , filepath | ||||
|                      , gtk-strut | ||||
|                      , gi-gtk | ||||
|                      , glib | ||||
|                      , gtk3>=0.14.8 | ||||
|                      , gtk-sni-tray | ||||
|                      , hslogger | ||||
|                      , mtl | ||||
|                      , haskell-gi-base | ||||
|                      , process | ||||
|   | ||||
| @@ -8,16 +8,10 @@ packages: | ||||
|     git: git@github.com:willdonnelly/dyre.git | ||||
|     commit: 11412752b483135e0c151ab90be17b217f837c4b | ||||
|   extra-dep: true | ||||
| - location: | ||||
|     git: git@github.com:IvanMalison/gtk-traymanager.git | ||||
|     commit: 517b24722b2cdab2dadbafa882ffcb6b8a1d01ff | ||||
|   extra-dep: true | ||||
| - location: ../xmonad/xmonad-contrib | ||||
|   extra-dep: true | ||||
| - location: ../../../../Projects/status-notifier-item | ||||
|   extra-dep: true | ||||
| - location: ../../../../Projects/haskell-dbus | ||||
|   extra-dep: true | ||||
| - location: ../../../../Projects/gtk-sni-tray | ||||
|   extra-dep: true | ||||
| - location: | ||||
| @@ -27,19 +21,24 @@ packages: | ||||
|       - gtk | ||||
|   extra-dep: true | ||||
| extra-deps: | ||||
| - spool-0.1 | ||||
| - X11-xft-0.3.1 | ||||
| - gio-0.13.4.1 | ||||
| - libxml-sax-0.7.5 | ||||
| - rate-limit-1.1.1 | ||||
| - time-units-1.0.0 | ||||
| - xml-helpers-1.0.0 | ||||
| - gi-dbusmenugtk3-0.4.1 | ||||
| - dbus-1.0.0 | ||||
| - gi-dbusmenu-0.4.1 | ||||
| - gi-dbusmenugtk3-0.4.1 | ||||
| - gi-gdk-3.0.15 | ||||
| - gi-gdkpixbuf-2.0.15 | ||||
| - gi-gtk-3.0.21 | ||||
| - gi-gdkx11-3.0.2 | ||||
| - gi-gio-2.0.16 | ||||
| - gi-gtk-3.0.21 | ||||
| - gi-pango-1.0.16 | ||||
| resolver: lts-10.5 | ||||
| - gi-xlib-2.0.2 | ||||
| - gio-0.13.4.1 | ||||
| - gtk-strut-0.1.2.0 | ||||
| - gtk-traymanager-1.0.1 | ||||
| - libxml-sax-0.7.5 | ||||
| - rate-limit-1.1.1 | ||||
| - spool-0.1 | ||||
| - time-units-1.0.0 | ||||
| - xml-helpers-1.0.0 | ||||
| resolver: lts-11.4 | ||||
| allow-newer: true | ||||
|   | ||||
 Submodule dotfiles/config/taffybar/taffybar updated: f7673d9053...1c2dbadc40
									
								
							| @@ -11,9 +11,10 @@ import                  Data.List | ||||
| import                  Data.List.Split | ||||
| import qualified        Data.Map as M | ||||
| import                  Data.Maybe | ||||
| import                  Debug.Trace | ||||
| import                  Foreign.ForeignPtr | ||||
| import                  Foreign.Ptr | ||||
| import qualified GI.Gtk.Objects.Widget as GI | ||||
| import qualified        GI.Gtk as GI | ||||
| import qualified "gtk3" Graphics.UI.Gtk as Gtk | ||||
| import qualified "gtk3" Graphics.UI.Gtk.Abstract.Widget as W | ||||
| import qualified "gtk3" Graphics.UI.Gtk.Layout.Table as T | ||||
| @@ -23,10 +24,13 @@ import                  System.Directory | ||||
| import                  System.Environment | ||||
| import                  System.FilePath.Posix | ||||
| import                  System.Glib.GObject | ||||
| import                  System.IO | ||||
| import                  System.Information.CPU | ||||
| import                  System.Information.EWMHDesktopInfo | ||||
| import                  System.Information.Memory | ||||
| import                  System.Information.X11DesktopInfo | ||||
| import                  System.Log.Handler.Simple | ||||
| import                  System.Log.Logger | ||||
| import                  System.Process | ||||
| import                  System.Taffybar | ||||
| import                  System.Taffybar.Battery | ||||
| @@ -34,14 +38,13 @@ import                  System.Taffybar.IconImages | ||||
| import                  System.Taffybar.LayoutSwitcher | ||||
| import                  System.Taffybar.MPRIS2 | ||||
| import                  System.Taffybar.NetMonitor | ||||
| import                  System.Taffybar.Pager | ||||
| import                  System.Taffybar.SimpleClock | ||||
| import                  System.Taffybar.SimpleConfig | ||||
| import                  System.Taffybar.Systray | ||||
| import                  System.Taffybar.ToggleMonitor | ||||
| import                  System.Taffybar.Widgets.PollingGraph | ||||
| import                  System.Taffybar.WindowSwitcher | ||||
| import                  System.Taffybar.WorkspaceHUD | ||||
| import                  System.Taffybar.WorkspaceSwitcher | ||||
| import                  Text.Printf | ||||
| import                  Text.Read hiding (lift) | ||||
| import                  Unsafe.Coerce | ||||
| @@ -123,28 +126,6 @@ underlineWidget cfg buildWidget name = do | ||||
|  | ||||
|   return $ Gtk.toWidget t | ||||
|  | ||||
| movableWidget builder = | ||||
|   do | ||||
|     -- Delay creation of the widget or else failure from trying to get screen | ||||
|     widVar <- MV.newEmptyMVar | ||||
|     let moveWidget = do | ||||
|           isEmpty <- MV.isEmptyMVar widVar | ||||
|           when isEmpty $ | ||||
|                do | ||||
|                  putwid <- builder | ||||
|                  MV.putMVar widVar putwid | ||||
|           wid <- MV.readMVar widVar | ||||
|           hbox <- Gtk.hBoxNew False 0 | ||||
|           parent <- Gtk.widgetGetParent wid | ||||
|           if isJust parent | ||||
|           then | ||||
|             Gtk.widgetReparent wid hbox | ||||
|           else | ||||
|             Gtk.containerAdd hbox wid | ||||
|           Gtk.widgetShowAll hbox | ||||
|           return $ Gtk.toWidget hbox | ||||
|     return moveWidget | ||||
|  | ||||
| myFormatEntry wsNames ((ws, wtitle, wclass), _) = | ||||
|   printf "%s: %s - %s" wsName (head $ splitOn "\NUL" wclass) wtitle | ||||
|   where | ||||
| @@ -157,18 +138,28 @@ getInterfaces = do | ||||
|  | ||||
| addClass klass action = do | ||||
|   widget <- action | ||||
|   widgetSetClass widget klass | ||||
|   lift $ widgetSetClass widget klass | ||||
|   return widget | ||||
|  | ||||
| (buildWidgetCons, _) = mkWidget | ||||
|  | ||||
| buildSNITray = do | ||||
|   GI.Widget trayGIWidgetMP <- buildTrayWithHost | ||||
|   -- XXX: this won't work for multiple taffybars because it will attempt to | ||||
|   -- register a second host with a name that already exists on the dbus tray. | ||||
|   -- Need to take an approach similar to that of gtk-sni-tray to get that to | ||||
|   -- work. | ||||
|   GI.Widget trayGIWidgetMP <- buildTrayWithHost GI.OrientationHorizontal | ||||
|   wrapNewGObject mkWidget (castPtr <$> disownManagedPtr trayGIWidgetMP) | ||||
|  | ||||
| logDebug = do | ||||
|   handler <- streamHandler stdout DEBUG | ||||
|   logger <- getLogger "System.Taffybar" | ||||
|   saveGlobalLogger $ setLevel DEBUG logger | ||||
|  | ||||
| main = do | ||||
|   interfaceNames <- getInterfaces | ||||
|   homeDirectory <- getHomeDirectory | ||||
|   logDebug | ||||
|   let resourcesDirectory = homeDirectory </> ".lib" </> "resources" | ||||
|       inResourcesDirectory file = resourcesDirectory </> file | ||||
|       highContrastDirectory = | ||||
| @@ -232,25 +223,29 @@ main = do | ||||
|         --       ] | ||||
|         , showWorkspaceFn = hideEmpty | ||||
|         , updateRateLimitMicroseconds = 100000 | ||||
|         , updateOnWMIconChange = True | ||||
|         , debugMode = False | ||||
|         , labelSetter = workspaceNamesLabelSetter | ||||
|         } | ||||
|       netMonitor = netMonitorMultiNew 1.5 interfaceNames | ||||
|       pagerConfig = | ||||
|         defaultPagerConfig | ||||
|         {useImages = True, windowSwitcherFormatter = myFormatEntry} | ||||
|       -- makeUnderline = underlineWidget myHUDConfig | ||||
|   pgr <- pagerNew pagerConfig | ||||
|   -- pgr <- pagerNew pagerConfig | ||||
|   -- tray2 <- movableWidget tray | ||||
|   let hud = buildWorkspaceHUD myHUDConfig pgr | ||||
|       los = layoutSwitcherNew pgr | ||||
|       wnd = windowSwitcherNew pgr | ||||
|       taffyConfig = | ||||
|         defaultTaffybarConfig | ||||
|   let hud = buildWorkspaceHUD myHUDConfig | ||||
|       los = layoutSwitcherNew defaultLayoutSwitcherConfig | ||||
|       wnd = windowSwitcherNew defaultWindowSwitcherConfig | ||||
|       simpleTaffyConfig = | ||||
|         defaultSimpleTaffyConfig | ||||
|         { startWidgets = [hud, los, addClass "WindowSwitcher" wnd] | ||||
|         , endWidgets = | ||||
|             [ batteryBarNewWithFormat defaultBatteryConfig "$percentage$% ($time$) - $status$" 1.0 | ||||
| ||||||| merged common ancestors | ||||
|         , endWidgets = | ||||
|             [ batteryBarNew defaultBatteryConfig 1.0 | ||||
| ======= | ||||
|         , centerWidgets = [] | ||||
|         , endWidgets = map lift | ||||
|             [ batteryBarNew defaultBatteryConfig 1.0 | ||||
| >>>>>>> b44e57a9f4ec822e99649b1ccc5516cbcbad4fb8 | ||||
|             , makeContents clock "Cpu" | ||||
|             -- , makeContents systrayNew "Cpu" | ||||
|             , makeContents buildSNITray "Cpu" | ||||
| @@ -261,10 +256,10 @@ main = do | ||||
|             ] | ||||
|         , barPosition = Top | ||||
|         , barPadding = 5 | ||||
|         , barHeight = (underlineHeight myHUDConfig + windowIconSize myHUDConfig + 10) | ||||
|         , barHeight = (underlineHeight myHUDConfig + windowIconSize myHUDConfig + 15) | ||||
|         , widgetSpacing = 0 | ||||
|         } | ||||
|   withToggleSupport taffyConfig | ||||
|   dyreTaffybar $ handleDBusToggles $ toTaffyConfig simpleTaffyConfig | ||||
|  | ||||
| -- Local Variables: | ||||
| -- flycheck-ghc-args: ("-Wno-missing-signatures") | ||||
|   | ||||
| @@ -1,134 +0,0 @@ | ||||
| style "taffybar-default" { | ||||
|   color["black"] = "#000000" | ||||
|   color["white"] = "#ffffff" | ||||
|  | ||||
|   color["green"] = "#4caf50" | ||||
|   color["yellow"] = "#ffeb3b" | ||||
|   color["orange"] = "#f4511e" | ||||
|   color["blue"] = "#2196f3" | ||||
|   color["red"] = "#F44336" | ||||
|   color["dgrey"] = "#212121" | ||||
|   color["ldgrey"] = "#333333" | ||||
|   color["mgrey"] = "#808080" | ||||
|   color["lldgrey"] = "#424242" | ||||
|   color["lgrey"] = "#bdbdbd" | ||||
|   color["teal"] = "#00796b" | ||||
|   color["bgrey"] = "#37474F" | ||||
|   color["bgreyl"] = "#546E7A" | ||||
|   color["activeWS"] = @yellow | ||||
|   color["visibleWS"] = @red | ||||
|  | ||||
|   color["base"] = @black | ||||
|   color["accent1"] = @dgrey | ||||
|   color["accent2"] = @ldgrey | ||||
|  | ||||
|   bg[NORMAL]   = @black | ||||
|   fg[NORMAL]   = @white | ||||
|   text[NORMAL] = @black | ||||
|   fg[PRELIGHT] = @yellow | ||||
| } | ||||
|  | ||||
| style "taffybar-active-window" = "taffybar-default" { | ||||
|   fg[NORMAL] = @white | ||||
| } | ||||
|  | ||||
| style "taffybar-notification-button" = "taffybar-default" { | ||||
|   text[NORMAL] = @red | ||||
|   fg[NORMAL]   = @red | ||||
| } | ||||
|  | ||||
| style "taffybar-workspace-border-active" = "taffybar-default" { | ||||
|   bg[NORMAL] = @yellow | ||||
| } | ||||
| style "taffybar-workspace-border-visible" = "taffybar-default" { | ||||
|   bg[NORMAL] = @orange | ||||
| } | ||||
| style "taffybar-workspace-border-empty" = "taffybar-default" { | ||||
|   bg[NORMAL] = @blue | ||||
| } | ||||
| style "taffybar-workspace-border-hidden" = "taffybar-default" { | ||||
|   bg[NORMAL] = @blue | ||||
| } | ||||
|  | ||||
| style "taffybar-icon-urgent" = "taffybar-default" { | ||||
|   bg[NORMAL] = @yellow | ||||
| } | ||||
|  | ||||
| style "taffybar-icon-active" = "taffybar-default" { | ||||
|   bg[NORMAL] = @teal | ||||
| } | ||||
|  | ||||
| style "taffybar-icon-minimized" = "taffybar-default" { | ||||
|   bg[NORMAL] = @red | ||||
| } | ||||
|  | ||||
| style "taffybar-workspace-contents-active" = "taffybar-default" { | ||||
|   bg[NORMAL] = @dgrey | ||||
| } | ||||
|  | ||||
| style "taffybar-workspace-contents-visible" = "taffybar-default" { | ||||
|   bg[NORMAL] = @black | ||||
| } | ||||
|  | ||||
| style "taffybar-hover-button" = "taffybar-default" { | ||||
|   bg[ACTIVE] = @yellow | ||||
|   bg[NORMAL] = @black | ||||
|   bg[PRELIGHT] = @yellow | ||||
|   text[PRELIGHT] = @yellow | ||||
| } | ||||
|  | ||||
| style "blue" = "taffybar-default" { | ||||
|   bg[NORMAL]= @blue | ||||
| } | ||||
| style "orange" = "taffybar-default" { | ||||
|   bg[NORMAL]= @orange | ||||
| } | ||||
| style "red" = "taffybar-default" { | ||||
|   bg[NORMAL]= @red | ||||
| } | ||||
| style "yellow" = "taffybar-default" { | ||||
|   bg[NORMAL]= @yellow | ||||
| } | ||||
| style "green" = "taffybar-default" { | ||||
|   bg[NORMAL]= @green | ||||
| } | ||||
| style "teal" = "taffybar-default" { | ||||
|   bg[NORMAL]= @teal | ||||
| } | ||||
| style "bgrey" = "taffybar-default" { | ||||
|   bg[NORMAL]= @bgrey | ||||
| } | ||||
|  | ||||
| widget "Taffybar*" style "taffybar-default" | ||||
| widget "*WindowTitle*" style "taffybar-active-window" | ||||
| widget "*NotificationCloseButton" style "taffybar-notification-button" | ||||
|  | ||||
| widget "*Workspace-underline*-active*" style "taffybar-workspace-border-active" | ||||
| widget "*Workspace-contents*-active*" style "taffybar-workspace-contents-active" | ||||
| widget "*Workspace-contents*-visible*" style "taffybar-workspace-contents-visible" | ||||
|  | ||||
| widget "*Workspace-underline*-visible*" style "taffybar-workspace-border-visible" | ||||
| widget "*Workspace-underline*-empty*" style "taffybar-workspace-border-empty" | ||||
| widget "*Workspace-underline*-hidden*" style "taffybar-workspace-border-hidden" | ||||
|  | ||||
| widget "*Workspace-Border*-active*" style "taffybar-workspace-border-active" | ||||
| widget "*Workspace-Container-*-active*" style "taffybar-default" | ||||
| widget "*Workspace-Border*-visible*" style "taffybar-workspace-border-visible" | ||||
| widget "*Workspace-Container-*-visible*" style "taffybar-default" | ||||
|  | ||||
| widget "*Workspace-icon*-urgent*" style "taffybar-icon-urgent" | ||||
| widget "*Workspace-icon*-active*" style "taffybar-icon-active" | ||||
| widget "*Workspace-icon*-minimized*" style "taffybar-icon-minimized" | ||||
|  | ||||
| widget "*WorkspaceHUD-*" style "taffybar-hover-button" | ||||
| widget "*WorkspaceHUD-*" style "taffybar-hover-button" | ||||
|  | ||||
| widget "*clock-underline*" style "taffybar-workspace-border-active" | ||||
| widget "*tray-underline*" style "taffybar-workspace-border-hidden" | ||||
| widget "*blue-underline*" style "blue" | ||||
| widget "*red-underline*" style "red" | ||||
| widget "*yellow-underline*" style "yellow" | ||||
| widget "*orange-underline*" style "orange" | ||||
| widget "*green-underline*" style "green" | ||||
| widget "*teal-underline*" style "teal" | ||||
| widget "*bgrey-underline*" style "bgrey" | ||||
| @@ -2134,6 +2134,12 @@ I don't use auto-complete at all, so I have set up a hook to automatically disab | ||||
|     (global-flycheck-mode)) | ||||
|   :diminish flycheck-mode) | ||||
| #+END_SRC | ||||
| * straight | ||||
| #+BEGIN_SRC emacs-lisp | ||||
| (use-package straight | ||||
|   :config | ||||
|   (setq straight-vc-git-auto-fast-forward t)) | ||||
| #+END_SRC | ||||
| * Major Modes | ||||
| ** Programming | ||||
| <<programminglanguages>> | ||||
|   | ||||
| @@ -1,59 +1,107 @@ | ||||
| #!/usr/bin/env zsh | ||||
| #!/usr/bin/env sh | ||||
|  | ||||
| export SYSTEMD_COLORS=0 | ||||
| term=${ROFI_SYSTEMD_TERM-termite -e} | ||||
| default_action=${ROFI_SYSTEMD_DEFAULT_ACTION-"list_actions"} | ||||
|  | ||||
| function user_units { | ||||
|     SYSTEMD_COLORS=0 systemctl --user list-unit-files | tail -n +2 | head -n -2 | | ||||
|         awk '{print $0 "  user"}' | ||||
| 	SYSTEMD_COLORS=0 systemctl --user list-unit-files | tail -n +2 | head -n -2 | | ||||
| 		awk '{print $0 "  user"}' | ||||
| } | ||||
|  | ||||
| function system_units { | ||||
|     systemctl list-unit-files | tail -n +2 | head -n -2 | | ||||
|         awk '{print $0 "  system"}' | ||||
| 	systemctl list-unit-files | tail -n +2 | head -n -2 | | ||||
| 		awk '{print $0 "  system"}' | ||||
| } | ||||
|  | ||||
| enable="Alt+e" | ||||
| disable="Alt+d" | ||||
| stop="Alt+k" | ||||
| restart="Alt+r" | ||||
| tail="Alt+t" | ||||
| list_actions="Alt+l" | ||||
|  | ||||
| all_actions="enable | ||||
| disable | ||||
| stop | ||||
| restart | ||||
| tail | ||||
| list_actions" | ||||
|  | ||||
| function select_service_and_act { | ||||
|     result=$(rofi -dmenu -i -p "systemd unit: " \ | ||||
|                   -kb-custom-1 "${enable}" \ | ||||
|                   -kb-custom-2 "${disable}" \ | ||||
|                   -kb-custom-3 "${stop}" \ | ||||
|                   -kb-custom-4 "${restart}") | ||||
| 	result=$(rofi -dmenu -i -p "systemd unit: " \ | ||||
| 	              -kb-custom-1 "${enable}" \ | ||||
| 	              -kb-custom-2 "${disable}" \ | ||||
| 	              -kb-custom-3 "${stop}" \ | ||||
| 	              -kb-custom-4 "${restart}" \ | ||||
| 	              -kb-custom-5 "${tail}" \ | ||||
| 	              -kb-custom-6 "${list_actions}") | ||||
|  | ||||
|     rofi_exit="$?" | ||||
|     selection="$(echo $result | sed -n 's/ \+/ /gp')" | ||||
| 	rofi_exit="$?" | ||||
|  | ||||
|     action="restart" | ||||
|     case "$rofi_exit" in | ||||
|         1) | ||||
|             exit | ||||
|             ;; | ||||
|         10) | ||||
|             action="enable" | ||||
|             ;; | ||||
|         11) | ||||
|             action="disable" | ||||
|             ;; | ||||
|         12) | ||||
|             action="stop" | ||||
|             ;; | ||||
|     esac | ||||
| 	case "$rofi_exit" in | ||||
| 		1) | ||||
| 			action="exit" | ||||
| 			exit 1 | ||||
| 			;; | ||||
| 		10) | ||||
| 			action="enable" | ||||
| 			;; | ||||
| 		11) | ||||
| 			action="disable" | ||||
| 			;; | ||||
| 		12) | ||||
| 			action="stop" | ||||
| 			;; | ||||
| 		13) | ||||
| 			action="restart" | ||||
| 			;; | ||||
| 		14) | ||||
| 			action="tail" | ||||
| 			;; | ||||
| 		15) | ||||
| 			action="list_actions" | ||||
| 			;; | ||||
| 		*) | ||||
| 			action="$default_action" | ||||
| 			;; | ||||
| 	esac | ||||
|  | ||||
|     service_name="$(printf $selection | awk '{ print $1 }' | tr -d ' ')" | ||||
|     is_user="$(printf $selection | awk '{ print $3 }' )" | ||||
| 	selection="$(echo $result | sed -n 's/ \+/ /gp')" | ||||
| 	service_name="$(echo $selection | awk '{ print $1 }' | tr -d ' ')" | ||||
| 	is_user="$(echo $selection | awk '{ print $3 }' )" | ||||
|  | ||||
|     case "$is_user" in | ||||
|         user*) | ||||
|             systemctl "$action" --user "$service_name" | ||||
|             ;; | ||||
|         system*) | ||||
|             sudo systemctl "$action" "$service_name" | ||||
|             ;; | ||||
|     esac | ||||
| 	case "$is_user" in | ||||
| 		user*) | ||||
| 			user_arg="--user" | ||||
| 			command="systemctl $user_arg" | ||||
| 			;; | ||||
| 		system*) | ||||
| 			user_arg="" | ||||
| 			command="sudo systemctl" | ||||
| 			;; | ||||
| 		*) | ||||
| 			command="systemctl" | ||||
| 	esac | ||||
|  | ||||
| 	to_run="$(get_command_with_args)" | ||||
| 	echo "Running $to_run" | ||||
| 	eval "$to_run" | ||||
| } | ||||
|  | ||||
| function get_command_with_args { | ||||
| 	case "$action" in | ||||
| 		"tail") | ||||
| 			echo "$term 'journalctl $user_arg -u $service_name -f'" | ||||
| 			;; | ||||
| 		"list_actions") | ||||
| 			action=$(echo "$all_actions" | rofi -dmenu -i -p "Select action: ") | ||||
| 			get_command_with_args | ||||
| 			;; | ||||
| 		*) | ||||
| 			echo "$command $action $service_name" | ||||
| 			;; | ||||
| 	esac | ||||
| } | ||||
|  | ||||
| { user_units; system_units; } | column -tc 1 | select_service_and_act | ||||
|   | ||||
							
								
								
									
										168
									
								
								dotfiles/lib/python/investment_optimization.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										168
									
								
								dotfiles/lib/python/investment_optimization.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,168 @@ | ||||
| #!/usr/bin/env python | ||||
| import heapq | ||||
| from collections import namedtuple | ||||
|  | ||||
|  | ||||
| BuyOpportunity = namedtuple( | ||||
|     'BuyOpportunity', | ||||
|     ['trans_yield', 'start', 'end'] | ||||
| ) | ||||
|  | ||||
|  | ||||
| def maximize_profit(num_transactions, prices): | ||||
|     minima, maxima = find_extrema(prices) | ||||
|     opp_queue, reverse_opp_queue = make_opportunity_queues( | ||||
|         minima, maxima, prices, | ||||
|     ) | ||||
|     if not opp_queue: | ||||
|         return [] | ||||
|  | ||||
|     largest_segment = opp_queue[0][1] | ||||
|     # Segments will be kept in sorted order | ||||
|     segments = [largest_segment] | ||||
|  | ||||
|     # Remove any reverse yields that are greater than the largest actual yield | ||||
|     # since they can never be realized anyway. | ||||
|     while (reverse_opp_queue and reverse_opp_queue[0][1].trans_yield >= | ||||
|            largest_segment.trans_yield): | ||||
|         heapq.heappop(reverse_opp_queue) | ||||
|  | ||||
|     def try_rev_opp(): | ||||
|         # It is okay to definitely pop here even though we don't know that we | ||||
|         # can actually use the opp for the following reason: | ||||
|         # Since the rev opp queue was selected OVER that of the opp queue, we | ||||
|         # KNOW that the bounding segment that includes this rev opp must have | ||||
|         # already been selected if it is going to be included at all (since it | ||||
|         # must have greater yield). | ||||
|         _, rev_opp_can = heapq.heappop(reverse_opp_queue) | ||||
|         for (seg_index, split_seg) in enumerate(segments): | ||||
|             if split_seg.end >= rev_opp_can.end: | ||||
|                 # Since segments is sorted, this must be the correct segment | ||||
|                 break | ||||
|         else: | ||||
|             return | ||||
|         if split_seg.start <= rev_opp_can.start: | ||||
|             # We found the containing segment | ||||
|             left_yield = prices[rev_opp_can.start] - prices[split_seg.start] | ||||
|             right_yield = prices[split_seg.end] - prices[rev_opp_can.end] | ||||
|             left_segment = BuyOpportunity(left_yield, split_seg.start, rev_opp_can.start) | ||||
|             right_segment = BuyOpportunity(right_yield, rev_opp_can.end, split_seg.end) | ||||
|             segments.pop(seg_index) | ||||
|             segments.insert(seg_index, left_segment) | ||||
|             segments.insert(seg_index + 1, right_segment) | ||||
|  | ||||
|     def try_opp(): | ||||
|         _, opp = heapq.heappop(opp_queue) | ||||
|         if not segments: | ||||
|             segments.append(opp) | ||||
|         insertion_index = 0 | ||||
|         for (index, seg) in enumerate(segments): | ||||
|             if seg.start >= opp.start: | ||||
|                 insertion_index = index | ||||
|                 break | ||||
|         else: | ||||
|             insertion_index = len(segments) | ||||
|             seg = None | ||||
|         previous_seg = segments[insertion_index - 1] if insertion_index > 0 else None | ||||
|  | ||||
|         if ((seg is None or seg.start >= opp.end) and | ||||
|             (previous_seg is None or previous_seg.end <= opp.start)): | ||||
|             # There is no overlap, so we can insert | ||||
|             segments.insert(insertion_index, opp) | ||||
|         else: | ||||
|             pass | ||||
|  | ||||
|     while (opp_queue or reverse_opp_queue) and len(segments) < num_transactions: | ||||
|         if not reverse_opp_queue: | ||||
|             try_opp() | ||||
|         elif not opp_queue: | ||||
|             try_rev_opp() | ||||
|         else: | ||||
|             opp_can = opp_queue[0][1] | ||||
|             rev_opp_can = reverse_opp_queue[0][1] | ||||
|  | ||||
|             if rev_opp_can.trans_yield > opp_can.trans_yield: | ||||
|                 try_rev_opp() | ||||
|             else: | ||||
|                 try_opp() | ||||
|  | ||||
|     return segments | ||||
|  | ||||
|  | ||||
| def make_opportunity_queues(minima, maxima, prices): | ||||
|     opp_queue = [] | ||||
|     reverse_opp_queue = [] | ||||
|     for min_index, minimum in enumerate(minima): | ||||
|         for max_index, maximum in enumerate(maxima): | ||||
|             transaction_yield = prices[maximum] - prices[minimum] | ||||
|             if transaction_yield < 0: | ||||
|                 # We can ignore this pair because the transaction has negative | ||||
|                 # yield. | ||||
|                 continue | ||||
|             # minimum comes before maximum in time | ||||
|             if minimum < maximum: | ||||
|                 # Transaction yield is made negative because heapq is a min-heap | ||||
|                 heapq.heappush( | ||||
|                     opp_queue, ((-transaction_yield, maximum - minimum), BuyOpportunity( | ||||
|                         transaction_yield, minimum, maximum, | ||||
|                     )), | ||||
|                 ) | ||||
|             else: | ||||
|                 heapq.heappush( | ||||
|                     reverse_opp_queue, (-transaction_yield, BuyOpportunity( | ||||
|                         transaction_yield, maximum, minimum, | ||||
|                     )) | ||||
|                 ) | ||||
|     return opp_queue, reverse_opp_queue | ||||
|  | ||||
|  | ||||
| def find_extrema(prices): | ||||
|     maxima = [] | ||||
|     minima = [] | ||||
|     length_of_prices = len(prices) | ||||
|     if length_of_prices < 2: | ||||
|         return minima, maxima | ||||
|  | ||||
|     upwards = None | ||||
|     last = prices[0] | ||||
|  | ||||
|     for (index, price) in enumerate(prices): | ||||
|         if price < last: | ||||
|             if upwards is True: | ||||
|                 maxima.append(index - 1) | ||||
|             elif upwards is None: | ||||
|                 # We set the starting price as a maximum, but theres no point | ||||
|                 # since we would really never buy. | ||||
|                 maxima.append(0) | ||||
|                 pass | ||||
|             upwards = False | ||||
|         elif price > last: | ||||
|             if upwards is False: | ||||
|                 minima.append(index - 1) | ||||
|             elif upwards is None: | ||||
|                 # The starting value is a minimum | ||||
|                 minima.append(0) | ||||
|             upwards = True | ||||
|         last = price | ||||
|  | ||||
|     if upwards is True: | ||||
|         maxima.append(length_of_prices - 1) | ||||
|     elif upwards is False: | ||||
|         minima.append(length_of_prices - 1) | ||||
|  | ||||
|     return minima, maxima | ||||
|  | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     print (maximize_profit(10, [0, 1, 3, 2, 3, 0, 10, 12, 1, 2, 3, 2, 0, 2, 4, 3, 6, 4, 14, 1, 0, 2, 4, 5, 4, 5, 6])) | ||||
|  | ||||
|     print [ | ||||
|         BuyOpportunity(trans_yield=1, start=0, end=1), | ||||
|         BuyOpportunity(trans_yield=12, start=2, end=4), | ||||
|         BuyOpportunity(trans_yield=2, start=5, end=7), | ||||
|         BuyOpportunity(trans_yield=6, start=9, end=11), | ||||
|         BuyOpportunity(trans_yield=6, start=12, end=13), | ||||
|         BuyOpportunity(trans_yield=10, start=14, end=15), | ||||
|         BuyOpportunity(trans_yield=5, start=17, end=20), | ||||
|         BuyOpportunity(trans_yield=2, start=21, end=23), | ||||
|     ] | ||||
		Reference in New Issue
	
	Block a user