{"action":"created","issue":{"url":"https://api.github.com/repos/SublimeTextIssues/Core/issues/2547","repository_url":"https://api.github.com/repos/SublimeTextIssues/Core","labels_url":"https://api.github.com/repos/SublimeTextIssues/Core/issues/2547/labels{/name}","comments_url":"https://api.github.com/repos/SublimeTextIssues/Core/issues/2547/comments","events_url":"https://api.github.com/repos/SublimeTextIssues/Core/issues/2547/events","html_url":"https://github.com/SublimeTextIssues/Core/issues/2547","id":396081053,"node_id":"MDU6SXNzdWUzOTYwODEwNTM=","number":2547,"title":"Restore the `output.exec` panel view cursor and scroll position after building a project","user":{"login":"evandrocoan","id":5332158,"node_id":"MDQ6VXNlcjUzMzIxNTg=","avatar_url":"https://avatars0.githubusercontent.com/u/5332158?v=4","gravatar_id":"","url":"https://api.github.com/users/evandrocoan","html_url":"https://github.com/evandrocoan","followers_url":"https://api.github.com/users/evandrocoan/followers","following_url":"https://api.github.com/users/evandrocoan/following{/other_user}","gists_url":"https://api.github.com/users/evandrocoan/gists{/gist_id}","starred_url":"https://api.github.com/users/evandrocoan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/evandrocoan/subscriptions","organizations_url":"https://api.github.com/users/evandrocoan/orgs","repos_url":"https://api.github.com/users/evandrocoan/repos","events_url":"https://api.github.com/users/evandrocoan/events{/privacy}","received_events_url":"https://api.github.com/users/evandrocoan/received_events","type":"User","site_admin":false},"labels":[{"id":36959200,"node_id":"MDU6TGFiZWwzNjk1OTIwMA==","url":"https://api.github.com/repos/SublimeTextIssues/Core/labels/C:%20Build%20Systems","name":"C: Build Systems","color":"669933","default":false},{"id":37304112,"node_id":"MDU6TGFiZWwzNzMwNDExMg==","url":"https://api.github.com/repos/SublimeTextIssues/Core/labels/S:%20trivial","name":"S: trivial","color":"F7C9B2","default":false},{"id":36869002,"node_id":"MDU6TGFiZWwzNjg2OTAwMg==","url":"https://api.github.com/repos/SublimeTextIssues/Core/labels/T:%20enhancement","name":"T: enhancement","color":"1975E7","default":false}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":2,"created_at":"2019-01-04T21:56:16Z","updated_at":"2019-01-05T16:37:34Z","closed_at":null,"author_association":"NONE","body":"### Problem description\r\n\r\nAfter building a project and the output build panel show up, you scroll around and move the caret. Currently, rebuilding the project looses the last caret and scroll position.\r\n\r\n\r\n### Preferred solution\r\n\r\nCreate the new default setting `restore_output_view_scroll`:\r\n```js\r\n    // Restores the `output.exec` panel view cursor and scroll position after building a project\r\n    \"restore_output_view_scroll\": false,\r\n```\r\n\r\nThis settings would be have like the `word_wrap` setting, meaning it be be replaced per build system, i.e., I can define on the user settings `\"restore_output_view_scroll\": false,` but on the build system for Project X, I can define it as enabled:\r\n```js\r\n{\r\n    \"settings\":\r\n    {\r\n        \"restore_output_view_scroll\": true,\r\n    },\r\n}\r\n```\r\n\r\nOr:\r\n```js\r\n{\r\n    \"build_systems\":\r\n    [\r\n        {\r\n            \"name\": \"Call Tests\",\r\n            \"file_regex\": \"^[ ]*File \\\"(...*?)\\\", line ([0-9]*)\",\r\n\r\n            \"cmd\": [\"python\", \"tests.py\"],\r\n            \"working_dir\": \"$project_path/source\",\r\n\r\n            \"restore_output_view_scroll\": true,\r\n        },\r\n    ]\r\n}\r\n```\r\n\r\nPatch\r\n\r\n<details>\r\n<p>\r\n\r\n```diff\r\ndiff --git a/exec.py b/exec.py\r\n--- a/exec.py\r\n+++ b/exec.py\r\n@@ -12,6 +12,8 @@ import signal\r\n import sublime\r\n import sublime_plugin\r\n\r\n+g_last_scroll_positions = {}\r\n+\r\n\r\n class ProcessListener(object):\r\n     def on_data(self, proc, data):\r\n@@ -167,6 +169,67 @@ class AsyncProcess(object):\r\n                 break\r\n\r\n+class FixSublimeTextOutputBuild(sublime_plugin.WindowCommand):\r\n+\r\n+    def run(self, **kwargs) :\r\n+        window = self.window\r\n+        output_view = window.find_output_panel( \"exec\" )\r\n+\r\n+        # We need to save the view positions before the builtin `build` command run, because it\r\n+        # immediately erases the view contents.\r\n+        self.saveViewPositions( window, output_view )\r\n+\r\n+        window.run_command( 'build', kwargs )\r\n+\r\n+    def saveViewPositions(self, window, output_view):\r\n+\r\n+        if output_view:\r\n+            window_id = window.id()\r\n+            view_settings = window.active_view().settings()\r\n+\r\n+            if view_settings.get( 'restore_output_view_scroll' , False ):\r\n+\r\n+                g_last_scroll_positions[window_id] = (output_view.viewport_position(),\r\n+                        [(selection.begin(), selection.end()) for selection in output_view.sel()])\r\n+\r\n+            else:\r\n+                # Force to disable the scroll restoring, if the setting is disabled after being enabled\r\n+                g_last_scroll_positions[window_id] = (None, None)\r\n+\r\n class ExecCommand(sublime_plugin.WindowCommand, ProcessListener):\r\n     BLOCK_SIZE = 2**14\r\n     text_queue = collections.deque()\r\n@@ -299,39 +358,29 @@ class ExecCommand(sublime_plugin.WindowCommand, ProcessListener):\r\n             if not self.quiet:\r\n                 self.append_string(None, \"[Finished]\")\r\n\r\n+    def restoreViewPositions(self):\r\n+        window_id = self.window.id()\r\n+        if window_id in g_last_scroll_positions:\r\n+            last_scroll_region, last_caret_region = g_last_scroll_positions[window_id]\r\n+            if last_scroll_region:\r\n+                output_view = self.output_view\r\n+                def delayed_restore():\r\n+                    output_view.set_viewport_position(last_scroll_region)\r\n+                    output_view.sel().clear()\r\n\r\n+                    for selection in last_caret_region:\r\n+                        output_view.sel().add(sublime.Region(selection[0], selection[1]))\r\n\r\n+                sublime.set_timeout(delayed_restore, 0)\r\n\r\n     def is_enabled(self, kill=False, **kwargs):\r\n         if kill:\r\n@@ -372,6 +404,8 @@ class ExecCommand(sublime_plugin.WindowCommand, ProcessListener):\r\n         else:\r\n             sublime.status_message(\"Build finished with %d errors\" % len(errs))\r\n \r\n+        self.restoreViewPositions()\r\n+\r\n     def on_data(self, proc, data):\r\n         # Normalize newlines, Sublime Text always uses a single \\n separator\r\n         # in memory.\r\n\r\ndiff --git a/Default (Linux).sublime-keymap.hide b/Default (Linux).sublime-keymap.hide\r\n--- a/Default (Linux).sublime-keymap.hide   \r\n+++ b/Default (Linux).sublime-keymap.hide   \r\n@@ -368,13 +418,13 @@\r\n    // { \"keys\": [\"ctrl+f7\"], \"command\": \"cancel_build\" },\r\n    // { \"keys\": [\"ctrl+f7\"], \"command\": \"exec\", \"args\": {\"kill\": true} },\r\n \r\n-   { \"keys\": [\"f7\"], \"command\": \"build\" },\r\n-   { \"keys\": [\"ctrl+b\"], \"command\": \"build\" },\r\n+   { \"keys\": [\"f7\"], \"command\": \"fix_sublime_text_output_build\" },\r\n+   { \"keys\": [\"ctrl+b\"], \"command\": \"fix_sublime_text_output_build\" },\r\n \r\n    { \"keys\": [\"f8\"], \"command\": \"show_panel\", \"args\": {\"panel\": \"output.exec\"} },\r\n    { \"keys\": [\"f8\"], \"command\": \"cancel_build\", \"context\": [{ \"key\": \"panel\", \"operand\": \"output.exec\" }] },\r\n\r\ndiff --git a/Main.sublime-menu b/Main.sublime-menu\r\n--- a/Main.sublime-menu\r\n+++ b/Main.sublime-menu\r\n@@ -771,8 +771,8 @@\r\n                     { \"command\": \"new_build_system\", \"caption\": \"New Build System...\" }\r\n                 ]\r\n             },\r\n-            { \"command\": \"build\", \"mnemonic\": \"B\" },\r\n-            { \"command\": \"build\", \"args\": {\"select\": true}, \"caption\": \"Build With...\" },\r\n+            { \"command\": \"fix_sublime_text_output_build\", \"mnemonic\": \"B\", \"caption\": \"Build\" },\r\n+            { \"command\": \"fix_sublime_text_output_build\", \"args\": {\"select\": true}, \"caption\": \"Build With...\" },\r\n             { \"command\": \"cancel_build\", \"caption\": \"Cancel Build\", \"mnemonic\": \"C\" },\r\n             {\r\n                 \"caption\": \"Build Results\",\r\n```\r\n</p>\r\n</details><br>\r\n\r\n___ \r\n### Related issues\r\n1. https://github.com/SublimeTextIssues/Core/issues/2237 Remember the output panel word wrap setting between different builds"},"comment":{"url":"https://api.github.com/repos/SublimeTextIssues/Core/issues/comments/451669839","html_url":"https://github.com/SublimeTextIssues/Core/issues/2547#issuecomment-451669839","issue_url":"https://api.github.com/repos/SublimeTextIssues/Core/issues/2547","id":451669839,"node_id":"MDEyOklzc3VlQ29tbWVudDQ1MTY2OTgzOQ==","user":{"login":"FichteFoll","id":931051,"node_id":"MDQ6VXNlcjkzMTA1MQ==","avatar_url":"https://avatars1.githubusercontent.com/u/931051?v=4","gravatar_id":"","url":"https://api.github.com/users/FichteFoll","html_url":"https://github.com/FichteFoll","followers_url":"https://api.github.com/users/FichteFoll/followers","following_url":"https://api.github.com/users/FichteFoll/following{/other_user}","gists_url":"https://api.github.com/users/FichteFoll/gists{/gist_id}","starred_url":"https://api.github.com/users/FichteFoll/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/FichteFoll/subscriptions","organizations_url":"https://api.github.com/users/FichteFoll/orgs","repos_url":"https://api.github.com/users/FichteFoll/repos","events_url":"https://api.github.com/users/FichteFoll/events{/privacy}","received_events_url":"https://api.github.com/users/FichteFoll/received_events","type":"User","site_admin":false},"created_at":"2019-01-05T16:37:34Z","updated_at":"2019-01-05T16:37:34Z","author_association":"MEMBER","body":"As a suggestion, most test runners allow yout to can select a test case to run and ignore all the others, which is more suited for an interactive approach like running the tests through a terminal instead of ST as you're probably not looking to edit a custom build system all the time."}}
{"actor":{"display_login":"FichteFoll"}}