Comparar commits
13 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| b6d8d5d100 | |||
| 34f624c895 | |||
| d554b7fd03 | |||
| a61dff6e21 | |||
| 47b820ce7d | |||
| 33557b87eb | |||
| aed0c16acc | |||
| ecfb505144 | |||
| 54b60a5253 | |||
| 6dfbd5733d | |||
| e56fa3ec4f | |||
| fe0d714710 | |||
| 63a80a4d4d |
+2
-3
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "atom",
|
||||
"productName": "Atom",
|
||||
"version": "0.86.0",
|
||||
"version": "0.88.0",
|
||||
"description": "A hackable text editor for the 21st Century.",
|
||||
"main": "./src/browser/main.js",
|
||||
"repository": {
|
||||
@@ -30,7 +30,6 @@
|
||||
"grim": "0.6.0",
|
||||
"guid": "0.0.10",
|
||||
"jasmine-tagged": "^1.1.1",
|
||||
"keytar": "1.x",
|
||||
"less-cache": "0.12.0",
|
||||
"mixto": "1.x",
|
||||
"mkdirp": "0.3.5",
|
||||
@@ -73,7 +72,7 @@
|
||||
"command-palette": "0.20.0",
|
||||
"dev-live-reload": "0.30.0",
|
||||
"exception-reporting": "0.17.0",
|
||||
"feedback": "0.29.0",
|
||||
"feedback": "0.30.0",
|
||||
"find-and-replace": "0.97.0",
|
||||
"fuzzy-finder": "0.49.0",
|
||||
"git-diff": "0.28.0",
|
||||
|
||||
+11
-53
@@ -33,21 +33,7 @@ describe "Project", ->
|
||||
deserializedProject.getBuffers()[0].destroy()
|
||||
expect(deserializedProject.getBuffers().length).toBe 0
|
||||
|
||||
describe "when an edit session is destroyed", ->
|
||||
it "removes edit session and calls destroy on buffer (if buffer is not referenced by other edit sessions)", ->
|
||||
editor = atom.project.openSync("a")
|
||||
anotherEditor = atom.project.openSync("a")
|
||||
|
||||
expect(atom.project.editors.length).toBe 2
|
||||
expect(editor.buffer).toBe anotherEditor.buffer
|
||||
|
||||
editor.destroy()
|
||||
expect(atom.project.editors.length).toBe 1
|
||||
|
||||
anotherEditor.destroy()
|
||||
expect(atom.project.editors.length).toBe 0
|
||||
|
||||
describe "when an edit session is saved and the project has no path", ->
|
||||
describe "when an editor is saved and the project has no path", ->
|
||||
it "sets the project's path to the saved file's parent directory", ->
|
||||
tempFile = temp.openSync().path
|
||||
atom.project.setPath(undefined)
|
||||
@@ -56,73 +42,49 @@ describe "Project", ->
|
||||
editor.saveAs(tempFile)
|
||||
expect(atom.project.getPath()).toBe path.dirname(tempFile)
|
||||
|
||||
describe "when an edit session is copied", ->
|
||||
it "emits an 'editor-created' event and stores the edit session", ->
|
||||
handler = jasmine.createSpy('editorCreatedHandler')
|
||||
atom.project.on 'editor-created', handler
|
||||
|
||||
editor1 = atom.project.openSync("a")
|
||||
expect(handler.callCount).toBe 1
|
||||
expect(atom.project.getEditors().length).toBe 1
|
||||
expect(atom.project.getEditors()[0]).toBe editor1
|
||||
|
||||
editor2 = editor1.copy()
|
||||
expect(handler.callCount).toBe 2
|
||||
expect(atom.project.getEditors().length).toBe 2
|
||||
expect(atom.project.getEditors()[0]).toBe editor1
|
||||
expect(atom.project.getEditors()[1]).toBe editor2
|
||||
|
||||
describe ".openSync(path)", ->
|
||||
[absolutePath, newBufferHandler, newEditorHandler] = []
|
||||
[absolutePath, newBufferHandler] = []
|
||||
beforeEach ->
|
||||
absolutePath = require.resolve('./fixtures/dir/a')
|
||||
newBufferHandler = jasmine.createSpy('newBufferHandler')
|
||||
atom.project.on 'buffer-created', newBufferHandler
|
||||
newEditorHandler = jasmine.createSpy('newEditorHandler')
|
||||
atom.project.on 'editor-created', newEditorHandler
|
||||
|
||||
describe "when given an absolute path that hasn't been opened previously", ->
|
||||
it "returns a new edit session for the given path and emits 'buffer-created' and 'editor-created' events", ->
|
||||
it "returns a new edit session for the given path and emits 'buffer-created'", ->
|
||||
editor = atom.project.openSync(absolutePath)
|
||||
expect(editor.buffer.getPath()).toBe absolutePath
|
||||
expect(newBufferHandler).toHaveBeenCalledWith editor.buffer
|
||||
expect(newEditorHandler).toHaveBeenCalledWith editor
|
||||
|
||||
describe "when given a relative path that hasn't been opened previously", ->
|
||||
it "returns a new edit session for the given path (relative to the project root) and emits 'buffer-created' and 'editor-created' events", ->
|
||||
it "returns a new edit session for the given path (relative to the project root) and emits 'buffer-created'", ->
|
||||
editor = atom.project.openSync('a')
|
||||
expect(editor.buffer.getPath()).toBe absolutePath
|
||||
expect(newBufferHandler).toHaveBeenCalledWith editor.buffer
|
||||
expect(newEditorHandler).toHaveBeenCalledWith editor
|
||||
|
||||
describe "when passed the path to a buffer that has already been opened", ->
|
||||
it "returns a new edit session containing previously opened buffer and emits a 'editor-created' event", ->
|
||||
it "returns a new edit session containing previously opened buffer", ->
|
||||
editor = atom.project.openSync(absolutePath)
|
||||
newBufferHandler.reset()
|
||||
expect(atom.project.openSync(absolutePath).buffer).toBe editor.buffer
|
||||
expect(atom.project.openSync('a').buffer).toBe editor.buffer
|
||||
expect(newBufferHandler).not.toHaveBeenCalled()
|
||||
expect(newEditorHandler).toHaveBeenCalledWith editor
|
||||
|
||||
describe "when not passed a path", ->
|
||||
it "returns a new edit session and emits 'buffer-created' and 'editor-created' events", ->
|
||||
it "returns a new edit session and emits 'buffer-created'", ->
|
||||
editor = atom.project.openSync()
|
||||
expect(editor.buffer.getPath()).toBeUndefined()
|
||||
expect(newBufferHandler).toHaveBeenCalledWith(editor.buffer)
|
||||
expect(newEditorHandler).toHaveBeenCalledWith editor
|
||||
|
||||
describe ".open(path)", ->
|
||||
[absolutePath, newBufferHandler, newEditorHandler] = []
|
||||
[absolutePath, newBufferHandler] = []
|
||||
|
||||
beforeEach ->
|
||||
absolutePath = require.resolve('./fixtures/dir/a')
|
||||
newBufferHandler = jasmine.createSpy('newBufferHandler')
|
||||
atom.project.on 'buffer-created', newBufferHandler
|
||||
newEditorHandler = jasmine.createSpy('newEditorHandler')
|
||||
atom.project.on 'editor-created', newEditorHandler
|
||||
|
||||
describe "when given an absolute path that isn't currently open", ->
|
||||
it "returns a new edit session for the given path and emits 'buffer-created' and 'editor-created' events", ->
|
||||
it "returns a new edit session for the given path and emits 'buffer-created'", ->
|
||||
editor = null
|
||||
waitsForPromise ->
|
||||
atom.project.open(absolutePath).then (o) -> editor = o
|
||||
@@ -130,10 +92,9 @@ describe "Project", ->
|
||||
runs ->
|
||||
expect(editor.buffer.getPath()).toBe absolutePath
|
||||
expect(newBufferHandler).toHaveBeenCalledWith editor.buffer
|
||||
expect(newEditorHandler).toHaveBeenCalledWith editor
|
||||
|
||||
describe "when given a relative path that isn't currently opened", ->
|
||||
it "returns a new edit session for the given path (relative to the project root) and emits 'buffer-created' and 'editor-created' events", ->
|
||||
it "returns a new edit session for the given path (relative to the project root) and emits 'buffer-created'", ->
|
||||
editor = null
|
||||
waitsForPromise ->
|
||||
atom.project.open(absolutePath).then (o) -> editor = o
|
||||
@@ -141,10 +102,9 @@ describe "Project", ->
|
||||
runs ->
|
||||
expect(editor.buffer.getPath()).toBe absolutePath
|
||||
expect(newBufferHandler).toHaveBeenCalledWith editor.buffer
|
||||
expect(newEditorHandler).toHaveBeenCalledWith editor
|
||||
|
||||
describe "when passed the path to a buffer that is currently opened", ->
|
||||
it "returns a new edit session containing currently opened buffer and emits a 'editor-created' event", ->
|
||||
it "returns a new edit session containing currently opened buffer", ->
|
||||
editor = null
|
||||
waitsForPromise ->
|
||||
atom.project.open(absolutePath).then (o) -> editor = o
|
||||
@@ -154,10 +114,9 @@ describe "Project", ->
|
||||
expect(atom.project.openSync(absolutePath).buffer).toBe editor.buffer
|
||||
expect(atom.project.openSync('a').buffer).toBe editor.buffer
|
||||
expect(newBufferHandler).not.toHaveBeenCalled()
|
||||
expect(newEditorHandler).toHaveBeenCalledWith editor
|
||||
|
||||
describe "when not passed a path", ->
|
||||
it "returns a new edit session and emits 'buffer-created' and 'editor-created' events", ->
|
||||
it "returns a new edit session and emits 'buffer-created'", ->
|
||||
editor = null
|
||||
waitsForPromise ->
|
||||
atom.project.open().then (o) -> editor = o
|
||||
@@ -165,7 +124,6 @@ describe "Project", ->
|
||||
runs ->
|
||||
expect(editor.buffer.getPath()).toBeUndefined()
|
||||
expect(newBufferHandler).toHaveBeenCalledWith(editor.buffer)
|
||||
expect(newEditorHandler).toHaveBeenCalledWith editor
|
||||
|
||||
it "returns number of read bytes as progress indicator", ->
|
||||
filePath = atom.project.resolve 'a'
|
||||
|
||||
@@ -5,7 +5,7 @@ describe "Workspace", ->
|
||||
|
||||
beforeEach ->
|
||||
atom.project.setPath(atom.project.resolve('dir'))
|
||||
workspace = new Workspace
|
||||
atom.workspace = workspace = new Workspace
|
||||
|
||||
describe "::open(uri, options)", ->
|
||||
beforeEach ->
|
||||
@@ -152,6 +152,18 @@ describe "Workspace", ->
|
||||
workspace.open("bar://baz").then (item) ->
|
||||
expect(item).toEqual { bar: "bar://baz" }
|
||||
|
||||
it "emits an 'editor-created' event", ->
|
||||
absolutePath = require.resolve('./fixtures/dir/a')
|
||||
newEditorHandler = jasmine.createSpy('newEditorHandler')
|
||||
workspace.on 'editor-created', newEditorHandler
|
||||
|
||||
editor = null
|
||||
waitsForPromise ->
|
||||
workspace.open(absolutePath).then (e) -> editor = e
|
||||
|
||||
runs ->
|
||||
expect(newEditorHandler).toHaveBeenCalledWith editor
|
||||
|
||||
describe "::openSync(uri, options)", ->
|
||||
[activePane, initialItemCount] = []
|
||||
|
||||
@@ -245,3 +257,26 @@ describe "Workspace", ->
|
||||
it "opens the license as plain-text in a buffer", ->
|
||||
waitsForPromise -> workspace.openLicense()
|
||||
runs -> expect(workspace.activePaneItem.getText()).toMatch /Copyright/
|
||||
|
||||
describe "when an editor is destroyed", ->
|
||||
it "removes the editor", ->
|
||||
editor = null
|
||||
|
||||
waitsForPromise ->
|
||||
workspace.open("a").then (e) -> editor = e
|
||||
|
||||
runs ->
|
||||
expect(workspace.getEditors()).toHaveLength 1
|
||||
editor.destroy()
|
||||
expect(workspace.getEditors()).toHaveLength 0
|
||||
|
||||
describe "when an editor is copied", ->
|
||||
it "emits an 'editor-created' event", ->
|
||||
handler = jasmine.createSpy('editorCreatedHandler')
|
||||
workspace.on 'editor-created', handler
|
||||
|
||||
editor1 = workspace.openSync("a")
|
||||
expect(handler.callCount).toBe 1
|
||||
|
||||
editor2 = editor1.copy()
|
||||
expect(handler.callCount).toBe 2
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
crypto = require 'crypto'
|
||||
ipc = require 'ipc'
|
||||
keytar = require 'keytar'
|
||||
os = require 'os'
|
||||
path = require 'path'
|
||||
remote = require 'remote'
|
||||
@@ -484,17 +483,6 @@ class Atom extends Model
|
||||
isReleasedVersion: ->
|
||||
@constructor.isReleasedVersion()
|
||||
|
||||
getGitHubAuthTokenName: ->
|
||||
'Atom GitHub API Token'
|
||||
|
||||
# Public: Set the the github token in the keychain
|
||||
setGitHubAuthToken: (token) ->
|
||||
keytar.replacePassword(@getGitHubAuthTokenName(), 'github', token)
|
||||
|
||||
# Public: Get the github token from the keychain
|
||||
getGitHubAuthToken: ->
|
||||
keytar.getPassword(@getGitHubAuthTokenName(), 'github')
|
||||
|
||||
# Public: Get the directory path to Atom's configuration area.
|
||||
#
|
||||
# Returns the absolute path to ~/.atom
|
||||
|
||||
+10
-10
@@ -527,7 +527,7 @@ class EditorView extends View
|
||||
|
||||
if @editor
|
||||
@saveScrollPositionForEditor()
|
||||
@editor.off(".editor")
|
||||
@unsubscribe(@editor)
|
||||
|
||||
@editor = editor
|
||||
|
||||
@@ -535,34 +535,34 @@ class EditorView extends View
|
||||
|
||||
@editor.setVisible(true)
|
||||
|
||||
@editor.on "destroyed", =>
|
||||
@subscribe @editor, "destroyed", =>
|
||||
@remove()
|
||||
|
||||
@editor.on "contents-conflicted.editor", =>
|
||||
@subscribe @editor, "contents-conflicted", =>
|
||||
@showBufferConflictAlert(@editor)
|
||||
|
||||
@editor.on "path-changed.editor", =>
|
||||
@subscribe @editor, "path-changed", =>
|
||||
@editor.reloadGrammar()
|
||||
@trigger 'editor:path-changed'
|
||||
|
||||
@editor.on "grammar-changed.editor", =>
|
||||
@subscribe @editor, "grammar-changed", =>
|
||||
@trigger 'editor:grammar-changed'
|
||||
|
||||
@editor.on 'selection-added.editor', (selection) =>
|
||||
@subscribe @editor, 'selection-added', (selection) =>
|
||||
@newCursors.push(selection.cursor)
|
||||
@newSelections.push(selection)
|
||||
@requestDisplayUpdate()
|
||||
|
||||
@editor.on 'screen-lines-changed.editor', (e) =>
|
||||
@subscribe @editor, 'screen-lines-changed', (e) =>
|
||||
@handleScreenLinesChange(e)
|
||||
|
||||
@editor.on 'scroll-top-changed.editor', (scrollTop) =>
|
||||
@subscribe @editor, 'scroll-top-changed', (scrollTop) =>
|
||||
@scrollTop(scrollTop)
|
||||
|
||||
@editor.on 'scroll-left-changed.editor', (scrollLeft) =>
|
||||
@subscribe @editor, 'scroll-left-changed', (scrollLeft) =>
|
||||
@scrollLeft(scrollLeft)
|
||||
|
||||
@editor.on 'soft-wrap-changed.editor', (softWrap) =>
|
||||
@subscribe @editor, 'soft-wrap-changed', (softWrap) =>
|
||||
@setSoftWrap(softWrap)
|
||||
|
||||
@trigger 'editor:path-changed'
|
||||
|
||||
+2
-4
@@ -182,7 +182,7 @@ class Editor extends Model
|
||||
@subscribe @$scrollTop, (scrollTop) => @emit 'scroll-top-changed', scrollTop
|
||||
@subscribe @$scrollLeft, (scrollLeft) => @emit 'scroll-left-changed', scrollLeft
|
||||
|
||||
atom.project.addEditor(this) if registerEditor
|
||||
atom.workspace?.editorAdded(this) if registerEditor
|
||||
|
||||
serializeParams: ->
|
||||
id: @id
|
||||
@@ -225,19 +225,17 @@ class Editor extends Model
|
||||
@buffer.release()
|
||||
@displayBuffer.destroy()
|
||||
@languageMode.destroy()
|
||||
atom.project?.removeEditor(this)
|
||||
|
||||
# Create an {Editor} with its initial state based on this object
|
||||
copy: ->
|
||||
tabLength = @getTabLength()
|
||||
displayBuffer = @displayBuffer.copy()
|
||||
softTabs = @getSoftTabs()
|
||||
newEditor = new Editor({@buffer, displayBuffer, tabLength, softTabs, suppressCursorCreation: true})
|
||||
newEditor = new Editor({@buffer, displayBuffer, tabLength, softTabs, suppressCursorCreation: true, registerEditor: true})
|
||||
newEditor.setScrollTop(@getScrollTop())
|
||||
newEditor.setScrollLeft(@getScrollLeft())
|
||||
for marker in @findMarkers(editorId: @id)
|
||||
marker.copy(editorId: newEditor.id, preserveFolds: true)
|
||||
atom.project.addEditor(newEditor)
|
||||
newEditor
|
||||
|
||||
# Public: Get the title the editor's title for display in other parts of the
|
||||
|
||||
+6
-20
@@ -31,13 +31,11 @@ class Project extends Model
|
||||
|
||||
constructor: ({path, @buffers}={}) ->
|
||||
@buffers ?= []
|
||||
@openers = []
|
||||
|
||||
for buffer in @buffers
|
||||
do (buffer) =>
|
||||
buffer.once 'destroyed', => @removeBuffer(buffer)
|
||||
|
||||
@editors = []
|
||||
@setPath(path)
|
||||
|
||||
serializeParams: ->
|
||||
@@ -49,7 +47,6 @@ class Project extends Model
|
||||
params
|
||||
|
||||
destroyed: ->
|
||||
editor.destroy() for editor in @getEditors()
|
||||
buffer.destroy() for buffer in @getBuffers()
|
||||
@destroyRepo()
|
||||
|
||||
@@ -132,15 +129,6 @@ class Project extends Model
|
||||
filePath = @resolve(filePath)
|
||||
@buildEditorForBuffer(@bufferForPathSync(filePath), options)
|
||||
|
||||
# Add the given {Editor}.
|
||||
addEditor: (editor) ->
|
||||
@editors.push editor
|
||||
@emit 'editor-created', editor
|
||||
|
||||
# Return and removes the given {Editor}.
|
||||
removeEditor: (editor) ->
|
||||
_.remove(@editors, editor)
|
||||
|
||||
# Retrieves all the {TextBuffer}s in the project; that is, the
|
||||
# buffers for all open files.
|
||||
#
|
||||
@@ -153,7 +141,7 @@ class Project extends Model
|
||||
@findBufferForPath(@resolve(filePath))?.isModified()
|
||||
|
||||
findBufferForPath: (filePath) ->
|
||||
_.find @buffers, (buffer) -> buffer.getPath() == filePath
|
||||
_.find @buffers, (buffer) -> buffer.getPath() == filePath
|
||||
|
||||
# Only to be used in specs
|
||||
bufferForPathSync: (filePath) ->
|
||||
@@ -304,8 +292,7 @@ class Project extends Model
|
||||
deferred.promise
|
||||
|
||||
buildEditorForBuffer: (buffer, editorOptions) ->
|
||||
editor = new Editor(_.extend({buffer}, editorOptions))
|
||||
@addEditor(editor)
|
||||
editor = new Editor(_.extend({buffer, registerEditor: true}, editorOptions))
|
||||
editor
|
||||
|
||||
eachBuffer: (args...) ->
|
||||
@@ -321,20 +308,19 @@ class Project extends Model
|
||||
# Deprecated: delegate
|
||||
registerOpener: (opener) ->
|
||||
deprecate("Use Workspace::registerOpener instead")
|
||||
@openers.push(opener)
|
||||
atom.workspace.registerOpener(opener)
|
||||
|
||||
# Deprecated: delegate
|
||||
unregisterOpener: (opener) ->
|
||||
deprecate("Use Workspace::unregisterOpener instead")
|
||||
_.remove(@openers, opener)
|
||||
atom.workspace.unregisterOpener(opener)
|
||||
|
||||
# Deprecated: delegate
|
||||
eachEditor: (callback) ->
|
||||
deprecate("Use Workspace::eachEditor instead")
|
||||
callback(editor) for editor in @getEditors()
|
||||
@on 'editor-created', (editor) -> callback(editor)
|
||||
atom.workspace.eachEditor(callback)
|
||||
|
||||
# Deprecated: delegate
|
||||
getEditors: ->
|
||||
deprecate("Use Workspace::getEditors instead")
|
||||
new Array(@editors...)
|
||||
atom.workspace.getEditors()
|
||||
|
||||
+19
-7
@@ -1,10 +1,11 @@
|
||||
{deprecate} = require 'grim'
|
||||
{remove, last} = require 'underscore-plus'
|
||||
_ = require 'underscore-plus'
|
||||
{join} = require 'path'
|
||||
{Model} = require 'theorist'
|
||||
Q = require 'q'
|
||||
Serializable = require 'serializable'
|
||||
Delegator = require 'delegato'
|
||||
Editor = require './editor'
|
||||
PaneContainer = require './pane-container'
|
||||
Pane = require './pane'
|
||||
|
||||
@@ -28,6 +29,9 @@ class Workspace extends Model
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
@openers = []
|
||||
|
||||
@subscribe @paneContainer, 'item-destroyed', @onPaneItemDestroyed
|
||||
@registerOpener (filePath) =>
|
||||
switch filePath
|
||||
@@ -50,6 +54,9 @@ class Workspace extends Model
|
||||
paneContainer: @paneContainer.serialize()
|
||||
fullScreen: atom.isFullScreen()
|
||||
|
||||
editorAdded: (editor) ->
|
||||
@emit 'editor-created', editor
|
||||
|
||||
# Public: Register a function to be called for every current and future
|
||||
# {Editor} in the workspace.
|
||||
#
|
||||
@@ -58,13 +65,18 @@ class Workspace extends Model
|
||||
# Returns a subscription object with an `.off` method that you can call to
|
||||
# unregister the callback.
|
||||
eachEditor: (callback) ->
|
||||
atom.project.eachEditor(callback)
|
||||
callback(editor) for editor in @getEditors()
|
||||
@subscribe this, 'editor-created', (editor) -> callback(editor)
|
||||
|
||||
# Public: Get all current editors in the workspace.
|
||||
#
|
||||
# Returns an {Array} of {Editor}s.
|
||||
getEditors: ->
|
||||
atom.project.getEditors()
|
||||
editors = []
|
||||
for pane in @paneContainer.getPanes()
|
||||
editors.push(item) for item in pane.getItems() when item instanceof Editor
|
||||
|
||||
editors
|
||||
|
||||
# Public: Open a given a URI in Atom asynchronously.
|
||||
#
|
||||
@@ -172,14 +184,14 @@ class Workspace extends Model
|
||||
#
|
||||
# opener - A {Function} to be called when a path is being opened.
|
||||
registerOpener: (opener) ->
|
||||
atom.project.registerOpener(opener)
|
||||
@openers.push(opener)
|
||||
|
||||
# Public: Unregister an opener registered with {::registerOpener}.
|
||||
unregisterOpener: (opener) ->
|
||||
atom.project.unregisterOpener(opener)
|
||||
_.remove(@openers, opener)
|
||||
|
||||
getOpeners: ->
|
||||
atom.project.openers
|
||||
@openers
|
||||
|
||||
# Public: Get the active {Pane}.
|
||||
#
|
||||
@@ -262,7 +274,7 @@ class Workspace extends Model
|
||||
# Removes the item's uri from the list of potential items to reopen.
|
||||
itemOpened: (item) ->
|
||||
if uri = item.getUri?()
|
||||
remove(@destroyedItemUris, uri)
|
||||
_.remove(@destroyedItemUris, uri)
|
||||
|
||||
# Adds the destroyed item's uri to the list of items to reopen.
|
||||
onPaneItemDestroyed: (item) =>
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário